Skip to content

Commit

Permalink
better handling of attrs and slots instances
Browse files Browse the repository at this point in the history
  • Loading branch information
tclose committed Sep 1, 2023
1 parent 731177a commit 637f43c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 8 deletions.
18 changes: 10 additions & 8 deletions pydra/utils/hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,17 @@ def __bytes_repr__(self, cache: Cache) -> Iterator[bytes]:
def bytes_repr(obj: object, cache: Cache) -> Iterator[bytes]:
cls = obj.__class__
yield f"{cls.__module__}.{cls.__name__}:{{".encode()
try:
dct = obj.__dict__
except AttributeError as e:
# Attrs creates slots classes by default, so we add this here to handle those
# cases
if attrs.has(type(obj)):
# Drop any attributes that aren't used in comparisons by default
dct = attrs.asdict(obj, recurse=False, filter=lambda a, _: bool(a.eq)) # type: ignore
else:
try:
dct = attrs.asdict(obj, recurse=False) # type: ignore
except attrs.exceptions.NotAnAttrsClassError:
raise TypeError(f"Cannot hash {obj} as it is a slots class") from e
dct = obj.__dict__
except AttributeError as e:
try:
dct = {n: getattr(obj, n) for n in obj.__slots__} # type: ignore
except AttributeError:
raise e

Check warning on line 119 in pydra/utils/hash.py

View check run for this annotation

Codecov / codecov/patch

pydra/utils/hash.py#L118-L119

Added lines #L118 - L119 were not covered by tests
yield from bytes_repr_mapping_contents(dct, cache)
yield b"}"

Expand Down
23 changes: 23 additions & 0 deletions pydra/utils/tests/test_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ def __init__(self, x):
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)


def test_bytes_repr_slots_obj():
class MyClass:
__slots__ = ("x",)

def __init__(
self,
x,
):
self.x = x

obj_repr = join_bytes_repr(MyClass(1))
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)


def test_bytes_repr_attrs_slots():
@attrs.define
class MyClass:
Expand All @@ -144,6 +158,15 @@ class MyClass:
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)


def test_bytes_repr_attrs_no_slots():
@attrs.define(slots=False)
class MyClass:
x: int

obj_repr = join_bytes_repr(MyClass(1))
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)


def test_bytes_repr_type1():
obj_repr = join_bytes_repr(Path)
assert obj_repr == b"type:(pathlib.Path)"
Expand Down

0 comments on commit 637f43c

Please sign in to comment.