Skip to content

Commit

Permalink
fingerprinting base case handles empty __dict__
Browse files Browse the repository at this point in the history
  • Loading branch information
zilto committed Nov 25, 2024
1 parent 0bbc7f8 commit c701383
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 4 deletions.
6 changes: 5 additions & 1 deletion hamilton/caching/fingerprinting.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ def hash_value(obj, *args, depth=0, **kwargs) -> str:
if depth > MAX_DEPTH:
return UNHASHABLE

if hasattr(obj, "__dict__"):
# __dict__ attribute contains the instance attributes of the object.
# this is typically sufficient to define the object and its behavior, so it's a good target
# for a hash in the default case.
# Objects that return an empty dict should be skipped (very odd behavior, happens with pandas type)
if getattr(obj, "__dict__", {}) != {}:
return hash_value(obj.__dict__, depth=depth + 1)

# check if the object comes from a module part of the standard library
Expand Down
18 changes: 15 additions & 3 deletions tests/caching/test_fingerprinting.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,24 @@ def test_hash_no_dict_attribute():
class Foo:
__slots__ = ()

def __init__(self):
pass
obj = Foo()
assert not hasattr(obj, "__dict__")

fingerprint = fingerprinting.hash_value(obj)

assert fingerprint == fingerprinting.UNHASHABLE


def test_empty_dict_attr_is_unhashable():
"""Classes with an empty __dict__ can't be hashed during the base case."""

class Foo: ... # noqa: E701

obj = Foo()
assert obj.__dict__ == {}

fingerprint = fingerprinting.hash_value(obj)
assert not hasattr(obj, "__dict__")

assert fingerprint == fingerprinting.UNHASHABLE


Expand Down

0 comments on commit c701383

Please sign in to comment.