From 70990ed5cad5b886a7f595923724706a222c5945 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 22 Jul 2025 09:23:53 -0700 Subject: =?UTF-8?q?[3.14]=20Revert=20"[3.14]=20gh-135228:=20When=20@datacl?= =?UTF-8?q?ass(slots=3DTrue)=20replaces=E2=80=A6=20(#137013)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/dataclasses.py | 15 ---------- Lib/test/test_dataclasses/__init__.py | 35 ---------------------- .../2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst | 4 --- 3 files changed, 54 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 22b78bb..83ea623 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1338,13 +1338,6 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields): or _update_func_cell_for__class__(member.fdel, cls, newcls)): break - # gh-135228: Make sure the original class can be garbage collected. - # Bypass mapping proxy to allow __dict__ to be removed - old_cls_dict = cls.__dict__ | _deproxier - old_cls_dict.pop('__dict__', None) - if "__weakref__" in cls.__dict__: - del cls.__weakref__ - return newcls @@ -1739,11 +1732,3 @@ def _replace(self, /, **changes): # changes that aren't fields, this will correctly raise a # TypeError. return self.__class__(**changes) - - -# Hack to the get the underlying dict out of a mappingproxy -# Use it with: cls.__dict__ | _deproxier -class _Deproxier: - def __ror__(self, other): - return other -_deproxier = _Deproxier() diff --git a/Lib/test/test_dataclasses/__init__.py b/Lib/test/test_dataclasses/__init__.py index 6bf5e5b..e98a8f2 100644 --- a/Lib/test/test_dataclasses/__init__.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -3804,41 +3804,6 @@ class TestSlots(unittest.TestCase): # that we create internally. self.assertEqual(CorrectSuper.args, ["default", "default"]) - def test_original_class_is_gced(self): - # gh-135228: Make sure when we replace the class with slots=True, the original class - # gets garbage collected. - def make_simple(): - @dataclass(slots=True) - class SlotsTest: - pass - - return SlotsTest - - def make_with_annotations(): - @dataclass(slots=True) - class SlotsTest: - x: int - - return SlotsTest - - def make_with_annotations_and_method(): - @dataclass(slots=True) - class SlotsTest: - x: int - - def method(self) -> int: - return self.x - - return SlotsTest - - for make in (make_simple, make_with_annotations, make_with_annotations_and_method): - with self.subTest(make=make): - C = make() - support.gc_collect() - candidates = [cls for cls in object.__subclasses__() if cls.__name__ == 'SlotsTest' - and cls.__firstlineno__ == make.__code__.co_firstlineno + 1] - self.assertEqual(candidates, [C]) - class TestDescriptors(unittest.TestCase): def test_set_name(self): diff --git a/Misc/NEWS.d/next/Library/2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst b/Misc/NEWS.d/next/Library/2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst deleted file mode 100644 index ee8962c..0000000 --- a/Misc/NEWS.d/next/Library/2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst +++ /dev/null @@ -1,4 +0,0 @@ -When :mod:`dataclasses` replaces a class with a slotted dataclass, the -original class is now garbage collected again. Earlier changes in Python -3.14 caused this class to remain in existence together with the replacement -class synthesized by :mod:`dataclasses`. -- cgit v0.12