Skip to content

Commit abdab30

Browse files
committed
pythonGH-93521: Filter out __weakref__ slot if present in bases
1 parent 86a5e22 commit abdab30

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

Lib/dataclasses.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -1156,11 +1156,16 @@ def _add_slots(cls, is_frozen, weakref_slot):
11561156
itertools.chain.from_iterable(map(_get_slots, cls.__mro__[1:-1]))
11571157
)
11581158
# The slots for our class. Remove slots from our base classes. Add
1159-
# '__weakref__' if weakref_slot was given.
1159+
# '__weakref__' if weakref_slot was given, unless it is already present.
11601160
cls_dict["__slots__"] = tuple(
1161-
itertools.chain(
1162-
itertools.filterfalse(inherited_slots.__contains__, field_names),
1163-
("__weakref__",) if weakref_slot else ())
1161+
itertools.filterfalse(
1162+
inherited_slots.__contains__,
1163+
itertools.chain(
1164+
# gh-93521: '__weakref__' also needs to be filtered out if
1165+
# already present in inherited_slots
1166+
field_names, ('__weakref__',) if weakref_slot else ()
1167+
)
1168+
),
11641169
)
11651170

11661171
for field_name in field_names:

Lib/test/test_dataclasses.py

+16
Original file line numberDiff line numberDiff line change
@@ -3109,6 +3109,22 @@ def test_weakref_slot_make_dataclass(self):
31093109
"weakref_slot is True but slots is False"):
31103110
B = make_dataclass('B', [('a', int),], weakref_slot=True)
31113111

3112+
def test_weakref_slot_subclass_also_weakref_slot(self):
3113+
@dataclass(slots=True, weakref_slot=True)
3114+
class Base:
3115+
field: int
3116+
3117+
# A *can* also specify weakref_slot=True if it wants to (gh-93521)
3118+
@dataclass(slots=True, weakref_slot=True)
3119+
class A(Base):
3120+
...
3121+
3122+
# __weakref__ is in the base class, not A. But an instance of A
3123+
# is still weakref-able.
3124+
self.assertIn("__weakref__", Base.__slots__)
3125+
self.assertNotIn("__weakref__", A.__slots__)
3126+
a = A(1)
3127+
weakref.ref(a)
31123128

31133129
class TestDescriptors(unittest.TestCase):
31143130
def test_set_name(self):

0 commit comments

Comments
 (0)