From abdab302dae0b37297af4dd316db207b977a2fc0 Mon Sep 17 00:00:00 2001 From: Bluenix Date: Mon, 6 Jun 2022 15:05:13 +0200 Subject: [PATCH 1/4] GH-93521: Filter out `__weakref__` slot if present in bases --- Lib/dataclasses.py | 13 +++++++++---- Lib/test/test_dataclasses.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 4645ebfa71e71c..18ab69053fd520 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1156,11 +1156,16 @@ def _add_slots(cls, is_frozen, weakref_slot): itertools.chain.from_iterable(map(_get_slots, cls.__mro__[1:-1])) ) # The slots for our class. Remove slots from our base classes. Add - # '__weakref__' if weakref_slot was given. + # '__weakref__' if weakref_slot was given, unless it is already present. cls_dict["__slots__"] = tuple( - itertools.chain( - itertools.filterfalse(inherited_slots.__contains__, field_names), - ("__weakref__",) if weakref_slot else ()) + itertools.filterfalse( + inherited_slots.__contains__, + itertools.chain( + # gh-93521: '__weakref__' also needs to be filtered out if + # already present in inherited_slots + field_names, ('__weakref__',) if weakref_slot else () + ) + ), ) for field_name in field_names: diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index cf29cd07516f0d..1f607478324330 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3109,6 +3109,22 @@ def test_weakref_slot_make_dataclass(self): "weakref_slot is True but slots is False"): B = make_dataclass('B', [('a', int),], weakref_slot=True) + def test_weakref_slot_subclass_also_weakref_slot(self): + @dataclass(slots=True, weakref_slot=True) + class Base: + field: int + + # A *can* also specify weakref_slot=True if it wants to (gh-93521) + @dataclass(slots=True, weakref_slot=True) + class A(Base): + ... + + # __weakref__ is in the base class, not A. But an instance of A + # is still weakref-able. + self.assertIn("__weakref__", Base.__slots__) + self.assertNotIn("__weakref__", A.__slots__) + a = A(1) + weakref.ref(a) class TestDescriptors(unittest.TestCase): def test_set_name(self): From 5ee1d76fb4f7eca79ba17fc5ae4ac8c990fff2a2 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 13:19:44 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst diff --git a/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst b/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst new file mode 100644 index 00000000000000..0e19b428f0f0b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst @@ -0,0 +1 @@ +Allow specifying ``weakref_slot`` several times in dataclass MRO From 47a107ffc45842f72c6e387097374439e73a9e53 Mon Sep 17 00:00:00 2001 From: Bluenix Date: Mon, 6 Jun 2022 17:06:43 +0200 Subject: [PATCH 3/4] Expand test coverage of subclasses specifying `__weakref__` --- Lib/test/test_dataclasses.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 1f607478324330..98dfab481bfd14 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3109,7 +3109,7 @@ def test_weakref_slot_make_dataclass(self): "weakref_slot is True but slots is False"): B = make_dataclass('B', [('a', int),], weakref_slot=True) - def test_weakref_slot_subclass_also_weakref_slot(self): + def test_weakref_slot_subclass_weakref_slot(self): @dataclass(slots=True, weakref_slot=True) class Base: field: int @@ -3126,6 +3126,38 @@ class A(Base): a = A(1) weakref.ref(a) + def test_weakref_slot_subclass_no_weakref_slot(self): + @dataclass(slots=True, weakref_slot=True) + class Base: + field: int + + @dataclass(slots=True) + class A(Base): + ... + + # __weakref__ is in the base class, not A. Even though A doesn't + # specify weakref_slot, it should still be weakref-able. + self.assertIn("__weakref__", Base.__slots__) + self.assertNotIn("__weakref__", A.__slots__) + a = A(1) + weakref.ref(a) + + def test_weakref_slot_normal_base_weakref_slot(self): + class Base: + __slots__ = ('__weakref__',) + + @dataclass(slots=True, weakref_slot=True) + class A(Base): + field: int + + # __weakref__ is in the base class, not A. But an instance of + # A is still weakref-able. + self.assertIn("__weakref__", Base.__slots__) + self.assertNotIn("__weakref__", A.__slots__) + a = A(1) + weakref.ref(a) + + class TestDescriptors(unittest.TestCase): def test_set_name(self): # See bpo-33141. From 187a0fef6f661e8491b8e099ccd639ad5a48c79a Mon Sep 17 00:00:00 2001 From: Bluenix Date: Mon, 6 Jun 2022 17:17:24 +0200 Subject: [PATCH 4/4] Reword news blurb to explain change without context --- .../Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst b/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst index 0e19b428f0f0b5..3a3ff4736d2940 100644 --- a/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst +++ b/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst @@ -1 +1,4 @@ -Allow specifying ``weakref_slot`` several times in dataclass MRO +Fixed a case where dataclasses would try to add ``__weakref__`` into the +``__slots__`` for a dataclass that specified ``weakref_slot=True`` when it was +already defined in one of its bases. This resulted in a ``TypeError`` upon the +new class being created. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy