From 43185fb9395b6e15d6eac102f85f20087cf399b8 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 8 Apr 2025 21:22:57 +0300 Subject: [PATCH 1/3] gh-132285: Add a test when `__annotations__` is deleted --- Lib/test/test_annotationlib.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index f10282042c7430..58f5e2fa50e5a6 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -809,6 +809,24 @@ def f(x: int): {"x": "int"}, ) + def test_del_annotations(self): + # gh-132285 + called = False + class A: + def __annotate__(format): + nonlocal called + called = True + return {'a': int} + + self.assertEqual(A.__annotations__, {'a': int}) + self.assertTrue(called) + + del A.__annotations__ + called = False + + self.assertEqual(A.__annotations__, {'a': int}) + self.assertTrue(called) + def test_non_dict_annotations(self): class WeirdAnnotations: @property From 12e714fed99ef51f8579b85e4ebc5773fbfd92fe Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 9 Apr 2025 12:37:39 +0300 Subject: [PATCH 2/3] Address review --- Lib/test/test_annotationlib.py | 4 ++-- .../2025-04-09-12-37-31.gh-issue-132286.1ZdsOa.rst | 2 ++ Objects/typeobject.c | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-12-37-31.gh-issue-132286.1ZdsOa.rst diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index 58f5e2fa50e5a6..a09896545325e0 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -824,8 +824,8 @@ def __annotate__(format): del A.__annotations__ called = False - self.assertEqual(A.__annotations__, {'a': int}) - self.assertTrue(called) + self.assertEqual(A.__annotations__, {}) + self.assertFalse(called) def test_non_dict_annotations(self): class WeirdAnnotations: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-12-37-31.gh-issue-132286.1ZdsOa.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-12-37-31.gh-issue-132286.1ZdsOa.rst new file mode 100644 index 00000000000000..82dcbd3bc101de --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-12-37-31.gh-issue-132286.1ZdsOa.rst @@ -0,0 +1,2 @@ +Fix that :attr:`type.__annotate__` was not deleted, when +:attr:`type.__annotations__` was deleted. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b92eaefc90d0af..75c23ddd91b1a1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2066,8 +2066,7 @@ type_set_annotations(PyObject *tp, PyObject *value, void *Py_UNUSED(closure)) if (result < 0) { Py_DECREF(dict); return -1; - } - else if (result == 0) { + } else { // result can be 0 or 1 if (PyDict_Pop(dict, &_Py_ID(__annotate__), NULL) < 0) { PyType_Modified(type); Py_DECREF(dict); From 494c3e70fcaf6201cded097f5b554d09a3c0164b Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 9 Apr 2025 17:11:24 +0300 Subject: [PATCH 3/3] Address review --- Lib/test/test_annotationlib.py | 18 ------------------ Lib/test/test_type_annotations.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index a09896545325e0..f10282042c7430 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -809,24 +809,6 @@ def f(x: int): {"x": "int"}, ) - def test_del_annotations(self): - # gh-132285 - called = False - class A: - def __annotate__(format): - nonlocal called - called = True - return {'a': int} - - self.assertEqual(A.__annotations__, {'a': int}) - self.assertTrue(called) - - del A.__annotations__ - called = False - - self.assertEqual(A.__annotations__, {}) - self.assertFalse(called) - def test_non_dict_annotations(self): class WeirdAnnotations: @property diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index 9c70d27d29e89c..29e2c7a0cd837e 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -57,6 +57,26 @@ class C: del C.__annotations__ self.assertFalse("__annotations__" in C.__dict__) + def test_del_annotations_and_annotate(self): + # gh-132285 + called = False + class A: + def __annotate__(format): + nonlocal called + called = True + return {'a': int} + + self.assertEqual(A.__annotations__, {'a': int}) + self.assertTrue(called) + self.assertTrue(A.__annotate__) + + del A.__annotations__ + called = False + + self.assertEqual(A.__annotations__, {}) + self.assertFalse(called) + self.assertIs(A.__annotate__, None) + def test_descriptor_still_works(self): class C: def __init__(self, name=None, bases=None, d=None):