| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1199,10 +1199,17 @@ def _dataclass_setstate(self, state): | |||
| 1199 | 1199 | ||
| 1200 | 1200 | def _get_slots(cls): | |
| 1201 | 1201 | match cls.__dict__.get('__slots__'): | |
| 1202 | - # A class which does not define __slots__ at all is equivalent | ||
| 1203 | - # to a class defining __slots__ = ('__dict__', '__weakref__') | ||
| 1202 | + # `__dictoffset__` and `__weakrefoffset__` can tell us whether | ||
| 1203 | + # the base type has dict/weakref slots, in a way that works correctly | ||
| 1204 | + # for both Python classes and C extension types. Extension types | ||
| 1205 | + # don't use `__slots__` for slot creation | ||
| 1204 | 1206 | case None: | |
| 1205 | - yield from ('__dict__', '__weakref__') | ||
| 1207 | + slots = [] | ||
| 1208 | + if getattr(cls, '__weakrefoffset__', -1) != 0: | ||
| 1209 | + slots.append('__weakref__') | ||
| 1210 | + if getattr(cls, '__dictrefoffset__', -1) != 0: | ||
| 1211 | + slots.append('__dict__') | ||
| 1212 | + yield from slots | ||
| 1206 | 1213 | case str(slot): | |
| 1207 | 1214 | yield slot | |
| 1208 | 1215 | # Slots may be any iterable, but we cannot handle an iterator | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3515,8 +3515,114 @@ class A: | |||
| 3515 | 3515 | class B(A): | |
| 3516 | 3516 | pass | |
| 3517 | 3517 | ||
| 3518 | + self.assertEqual(B.__slots__, ()) | ||
| 3518 | 3519 | B() | |
| 3519 | 3520 | ||
| 3521 | + def test_dataclass_derived_generic(self): | ||
| 3522 | + T = typing.TypeVar('T') | ||
| 3523 | + | ||
| 3524 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3525 | + class A(typing.Generic[T]): | ||
| 3526 | + pass | ||
| 3527 | + self.assertEqual(A.__slots__, ('__weakref__',)) | ||
| 3528 | + self.assertTrue(A.__weakref__) | ||
| 3529 | + A() | ||
| 3530 | + | ||
| 3531 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3532 | + class B[T2]: | ||
| 3533 | + pass | ||
| 3534 | + self.assertEqual(B.__slots__, ('__weakref__',)) | ||
| 3535 | + self.assertTrue(B.__weakref__) | ||
| 3536 | + B() | ||
| 3537 | + | ||
| 3538 | + def test_dataclass_derived_generic_from_base(self): | ||
| 3539 | + T = typing.TypeVar('T') | ||
| 3540 | + | ||
| 3541 | + class RawBase: ... | ||
| 3542 | + | ||
| 3543 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3544 | + class C1(typing.Generic[T], RawBase): | ||
| 3545 | + pass | ||
| 3546 | + self.assertEqual(C1.__slots__, ()) | ||
| 3547 | + self.assertTrue(C1.__weakref__) | ||
| 3548 | + C1() | ||
| 3549 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3550 | + class C2(RawBase, typing.Generic[T]): | ||
| 3551 | + pass | ||
| 3552 | + self.assertEqual(C2.__slots__, ()) | ||
| 3553 | + self.assertTrue(C2.__weakref__) | ||
| 3554 | + C2() | ||
| 3555 | + | ||
| 3556 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3557 | + class D[T2](RawBase): | ||
| 3558 | + pass | ||
| 3559 | + self.assertEqual(D.__slots__, ()) | ||
| 3560 | + self.assertTrue(D.__weakref__) | ||
| 3561 | + D() | ||
| 3562 | + | ||
| 3563 | + def test_dataclass_derived_generic_from_slotted_base(self): | ||
| 3564 | + T = typing.TypeVar('T') | ||
| 3565 | + | ||
| 3566 | + class WithSlots: | ||
| 3567 | + __slots__ = ('a', 'b') | ||
| 3568 | + | ||
| 3569 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3570 | + class E1(WithSlots, Generic[T]): | ||
| 3571 | + pass | ||
| 3572 | + self.assertEqual(E1.__slots__, ('__weakref__',)) | ||
| 3573 | + self.assertTrue(E1.__weakref__) | ||
| 3574 | + E1() | ||
| 3575 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3576 | + class E2(Generic[T], WithSlots): | ||
| 3577 | + pass | ||
| 3578 | + self.assertEqual(E2.__slots__, ('__weakref__',)) | ||
| 3579 | + self.assertTrue(E2.__weakref__) | ||
| 3580 | + E2() | ||
| 3581 | + | ||
| 3582 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3583 | + class F[T2](WithSlots): | ||
| 3584 | + pass | ||
| 3585 | + self.assertEqual(F.__slots__, ('__weakref__',)) | ||
| 3586 | + self.assertTrue(F.__weakref__) | ||
| 3587 | + F() | ||
| 3588 | + | ||
| 3589 | + def test_dataclass_derived_generic_from_slotted_base(self): | ||
| 3590 | + T = typing.TypeVar('T') | ||
| 3591 | + | ||
| 3592 | + class WithWeakrefSlot: | ||
| 3593 | + __slots__ = ('__weakref__',) | ||
| 3594 | + | ||
| 3595 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3596 | + class G1(WithWeakrefSlot, Generic[T]): | ||
| 3597 | + pass | ||
| 3598 | + self.assertEqual(G1.__slots__, ()) | ||
| 3599 | + self.assertTrue(G1.__weakref__) | ||
| 3600 | + G1() | ||
| 3601 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3602 | + class G2(Generic[T], WithWeakrefSlot): | ||
| 3603 | + pass | ||
| 3604 | + self.assertEqual(G2.__slots__, ()) | ||
| 3605 | + self.assertTrue(G2.__weakref__) | ||
| 3606 | + G2() | ||
| 3607 | + | ||
| 3608 | + @dataclass(slots=True, weakref_slot=True) | ||
| 3609 | + class H[T2](WithWeakrefSlot): | ||
| 3610 | + pass | ||
| 3611 | + self.assertEqual(H.__slots__, ()) | ||
| 3612 | + self.assertTrue(H.__weakref__) | ||
| 3613 | + H() | ||
| 3614 | + | ||
| 3615 | + def test_dataclass_slot_dict(self): | ||
| 3616 | + class WithDictSlot: | ||
| 3617 | + __slots__ = ('__dict__',) | ||
| 3618 | + | ||
| 3619 | + @dataclass(slots=True) | ||
| 3620 | + class A(WithDictSlot): ... | ||
| 3621 | + | ||
| 3622 | + self.assertEqual(A.__slots__, ()) | ||
| 3623 | + self.assertEqual(A().__dict__, {}) | ||
| 3624 | + A() | ||
| 3625 | + | ||
| 3520 | 3626 | ||
| 3521 | 3627 | class TestDescriptors(unittest.TestCase): | |
| 3522 | 3628 | def test_set_name(self): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Fix :func:`dataclasses.dataclass` not creating a ``__weakref__`` slot when | ||
| 2 | + subclassing :class:`typing.Generic`. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments