Skip to content

Commit ff06fb1

Browse files
committed
better handling of attrs and slots instances
1 parent 87fad04 commit ff06fb1

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

pydra/utils/hash.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,17 @@ def __bytes_repr__(self, cache: Cache) -> Iterator[bytes]:
106106
def bytes_repr(obj: object, cache: Cache) -> Iterator[bytes]:
107107
cls = obj.__class__
108108
yield f"{cls.__module__}.{cls.__name__}:{{".encode()
109-
try:
110-
dct = obj.__dict__
111-
except AttributeError as e:
112-
# Attrs creates slots classes by default, so we add this here to handle those
113-
# cases
109+
if attrs.has(type(obj)):
110+
# Drop any attributes that aren't used in comparisons by default
111+
dct = attrs.asdict(obj, recurse=False, filter=lambda a, _: bool(a.eq)) # type: ignore
112+
else:
114113
try:
115-
dct = attrs.asdict(obj, recurse=False) # type: ignore
116-
except attrs.exceptions.NotAnAttrsClassError:
117-
raise TypeError(f"Cannot hash {obj} as it is a slots class") from e
114+
dct = obj.__dict__
115+
except AttributeError as e:
116+
try:
117+
dct = {n: getattr(obj, n) for n in obj.__slots__} # type: ignore
118+
except AttributeError:
119+
raise e
118120
yield from bytes_repr_mapping_contents(dct, cache)
119121
yield b"}"
120122

pydra/utils/tests/test_hash.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,20 @@ def __init__(self, x):
135135
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)
136136

137137

138+
def test_bytes_repr_slots_obj():
139+
class MyClass:
140+
__slots__ = ("x",)
141+
142+
def __init__(
143+
self,
144+
x,
145+
):
146+
self.x = x
147+
148+
obj_repr = join_bytes_repr(MyClass(1))
149+
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)
150+
151+
138152
def test_bytes_repr_attrs_slots():
139153
@attrs.define
140154
class MyClass:
@@ -144,6 +158,15 @@ class MyClass:
144158
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)
145159

146160

161+
def test_bytes_repr_attrs_no_slots():
162+
@attrs.define(slots=False)
163+
class MyClass:
164+
x: int
165+
166+
obj_repr = join_bytes_repr(MyClass(1))
167+
assert re.match(rb".*\.MyClass:{str:1:x=.{16}}", obj_repr)
168+
169+
147170
def test_bytes_repr_type1():
148171
obj_repr = join_bytes_repr(Path)
149172
assert obj_repr == b"type:(pathlib.Path)"

0 commit comments

Comments
 (0)