fix: handle __slots__-only objects in comparator
Objects with __slots__ but no __dict__ (e.g. textual.cache.LRUCache) fell through all comparator branches, logging "Unknown comparator input type" and returning False — causing spurious test mismatches.
This commit is contained in:
parent
eaff96fd45
commit
d8582c328a
2 changed files with 52 additions and 0 deletions
|
|
@ -561,6 +561,18 @@ def comparator(orig: Any, new: Any, superset_obj: bool = False) -> bool:
|
|||
new_keys = {k: v for k, v in new.__dict__.items() if k != "parent"}
|
||||
return comparator(orig_keys, new_keys, superset_obj)
|
||||
|
||||
# For objects with __slots__ but no __dict__, compare slot attributes
|
||||
if hasattr(type(orig), "__slots__"):
|
||||
all_slots = set()
|
||||
for cls in type(orig).__mro__:
|
||||
if hasattr(cls, "__slots__"):
|
||||
all_slots.update(cls.__slots__)
|
||||
orig_vals = {s: getattr(orig, s, None) for s in all_slots}
|
||||
new_vals = {s: getattr(new, s, None) for s in all_slots}
|
||||
if superset_obj:
|
||||
return all(k in new_vals and comparator(v, new_vals[k], superset_obj) for k, v in orig_vals.items())
|
||||
return comparator(orig_vals, new_vals, superset_obj)
|
||||
|
||||
if type(orig) in {types.BuiltinFunctionType, types.BuiltinMethodType}:
|
||||
return new == orig
|
||||
if str(type(orig)) == "<class 'object'>":
|
||||
|
|
|
|||
|
|
@ -5240,3 +5240,43 @@ class TestUnionType:
|
|||
|
||||
def test_union_type_vs_none(self):
|
||||
assert not comparator(int | str, None)
|
||||
|
||||
|
||||
class SlotsOnly:
|
||||
__slots__ = ("x", "y")
|
||||
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
|
||||
class SlotsInherited(SlotsOnly):
|
||||
__slots__ = ("z",)
|
||||
|
||||
def __init__(self, x, y, z):
|
||||
super().__init__(x, y)
|
||||
self.z = z
|
||||
|
||||
|
||||
class TestSlotsObjects:
|
||||
def test_slots_equal(self):
|
||||
assert comparator(SlotsOnly(1, 2), SlotsOnly(1, 2))
|
||||
|
||||
def test_slots_not_equal(self):
|
||||
assert not comparator(SlotsOnly(1, 2), SlotsOnly(1, 3))
|
||||
|
||||
def test_slots_inherited_equal(self):
|
||||
assert comparator(SlotsInherited(1, 2, 3), SlotsInherited(1, 2, 3))
|
||||
|
||||
def test_slots_inherited_not_equal(self):
|
||||
assert not comparator(SlotsInherited(1, 2, 3), SlotsInherited(1, 2, 4))
|
||||
|
||||
def test_slots_nested(self):
|
||||
a = SlotsOnly(SlotsOnly(1, 2), [3, 4])
|
||||
b = SlotsOnly(SlotsOnly(1, 2), [3, 4])
|
||||
assert comparator(a, b)
|
||||
|
||||
def test_slots_nested_not_equal(self):
|
||||
a = SlotsOnly(SlotsOnly(1, 2), [3, 4])
|
||||
b = SlotsOnly(SlotsOnly(1, 9), [3, 4])
|
||||
assert not comparator(a, b)
|
||||
|
|
|
|||
Loading…
Reference in a new issue