From 598e78f0031dd5547112d0f83ba42da32ba633ff Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 14 Aug 2025 19:50:31 -0700 Subject: [PATCH 1/3] Use sys._clear_type_descriptors() on 3.14 --- src/attr/_make.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index eb1cda9bb..5b0e4a933 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -870,18 +870,22 @@ def _create_slots_class(self): } if PY_3_14_PLUS: - # Clean up old dict to avoid leaks. - old_cls_dict = self._cls.__dict__ | _deproxier - old_cls_dict.pop("__dict__", None) - if "__weakref__" in self._cls.__dict__: - del self._cls.__weakref__ + # 3.14.0rc2+ + if hasattr(sys, "_clear_type_descriptors"): + sys._clear_type_descriptors(self._cls) + else: + # Clean up old dict to avoid leaks. + old_cls_dict = self._cls.__dict__ | _deproxier + old_cls_dict.pop("__dict__", None) + if "__weakref__" in self._cls.__dict__: + del self._cls.__weakref__ - # Manually bump internal version tag. - try: - self._cls.__abstractmethods__ = self._cls.__abstractmethods__ - except AttributeError: - self._cls.__abstractmethods__ = frozenset({"__init__"}) - del self._cls.__abstractmethods__ + # Manually bump internal version tag. + try: + self._cls.__abstractmethods__ = self._cls.__abstractmethods__ + except AttributeError: + self._cls.__abstractmethods__ = frozenset({"__init__"}) + del self._cls.__abstractmethods__ # If our class doesn't have its own implementation of __setattr__ # (either from the user or by us), check the bases, if one of them has From 056b61bfa524c05a0e5a4cccbc08c1e4393cd178 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 02:54:48 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/attr/_make.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index 5b0e4a933..b739534a9 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -882,7 +882,9 @@ def _create_slots_class(self): # Manually bump internal version tag. try: - self._cls.__abstractmethods__ = self._cls.__abstractmethods__ + self._cls.__abstractmethods__ = ( + self._cls.__abstractmethods__ + ) except AttributeError: self._cls.__abstractmethods__ = frozenset({"__init__"}) del self._cls.__abstractmethods__ From 32c334b22f9009b94b600120290a0f55e0b17f18 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 14 Aug 2025 22:10:09 -0700 Subject: [PATCH 3/3] No more deproxying --- src/attr/_make.py | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index b739534a9..0b60ffe2c 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -24,7 +24,6 @@ PY_3_10_PLUS, PY_3_11_PLUS, PY_3_13_PLUS, - PY_3_14_PLUS, _AnnotationExtractor, _get_annotations, get_generic_base, @@ -629,17 +628,6 @@ def evolve(*args, **changes): return cls(**changes) -# Hack to the get the underlying dict out of a mappingproxy -# Use it with: cls.__dict__ | _deproxier -# See: https://github.com/python/cpython/pull/136893 -class _Deproxier: - def __ror__(self, other): - return other - - -_deproxier = _Deproxier() - - class _ClassBuilder: """ Iteratively build *one* class. @@ -869,25 +857,9 @@ def _create_slots_class(self): if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") } - if PY_3_14_PLUS: - # 3.14.0rc2+ - if hasattr(sys, "_clear_type_descriptors"): - sys._clear_type_descriptors(self._cls) - else: - # Clean up old dict to avoid leaks. - old_cls_dict = self._cls.__dict__ | _deproxier - old_cls_dict.pop("__dict__", None) - if "__weakref__" in self._cls.__dict__: - del self._cls.__weakref__ - - # Manually bump internal version tag. - try: - self._cls.__abstractmethods__ = ( - self._cls.__abstractmethods__ - ) - except AttributeError: - self._cls.__abstractmethods__ = frozenset({"__init__"}) - del self._cls.__abstractmethods__ + # 3.14.0rc2+ + if hasattr(sys, "_clear_type_descriptors"): + sys._clear_type_descriptors(self._cls) # If our class doesn't have its own implementation of __setattr__ # (either from the user or by us), check the bases, if one of them has