From 4cb2d40830f437b12bb61790f05d93623565af6d Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 10 May 2024 05:24:54 -0700 Subject: [PATCH 1/3] gh-118895: Call PyType_Ready() on typing.NoDefault --- Include/internal/pycore_typevarobject.h | 1 + Lib/test/test_typing.py | 12 +++++++++++- .../2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst | 2 ++ Modules/_typingmodule.c | 3 +++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst diff --git a/Include/internal/pycore_typevarobject.h b/Include/internal/pycore_typevarobject.h index 80a2daf4efc16a..a368edebd622a1 100644 --- a/Include/internal/pycore_typevarobject.h +++ b/Include/internal/pycore_typevarobject.h @@ -18,6 +18,7 @@ extern int _Py_initialize_generic(PyInterpreterState *); extern void _Py_clear_generic_types(PyInterpreterState *); extern PyTypeObject _PyTypeAlias_Type; +extern PyTypeObject _PyNoDefault_Type; extern PyObject _Py_NoDefaultStruct; #ifdef __cplusplus diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 8dde8aedd2a2b1..3ee0d63f9f4372 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -10236,7 +10236,7 @@ def test_pickling(self): def test_constructor(self): self.assertIs(NoDefault, type(NoDefault)()) with self.assertRaises(TypeError): - NoDefault(1) + type(NoDefault)(1) def test_repr(self): self.assertEqual(repr(NoDefault), 'typing.NoDefault') @@ -10245,6 +10245,16 @@ def test_no_call(self): with self.assertRaises(TypeError): NoDefault() + def test_no_attributes(self): + with self.assertRaises(AttributeError): + NoDefault.foo = 3 + with self.assertRaises(AttributeError): + NoDefault.foo + + # TypeError is consistent with the behavior of NoneType + with self.assertRaises(TypeError): + type(NoDefault).foo = 3 + class AllTests(BaseTestCase): """Tests for __all__.""" diff --git a/Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst b/Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst new file mode 100644 index 00000000000000..226c8d612a039c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst @@ -0,0 +1,2 @@ +Setting attributes on :data:`typing.NoDefault` now raises +:exc:`AttributeError` instead of :exc:`TypeError`. diff --git a/Modules/_typingmodule.c b/Modules/_typingmodule.c index 09fbb3c5e8b91d..37af00f3071e1d 100644 --- a/Modules/_typingmodule.c +++ b/Modules/_typingmodule.c @@ -63,6 +63,9 @@ _typing_exec(PyObject *m) if (PyModule_AddObjectRef(m, "TypeAliasType", (PyObject *)&_PyTypeAlias_Type) < 0) { return -1; } + if (PyType_Ready(&_PyNoDefault_Type) < 0) { + return -1; + } if (PyModule_AddObjectRef(m, "NoDefault", (PyObject *)&_Py_NoDefaultStruct) < 0) { return -1; } From 3b7eefacc763a949b211737023df8e9723b49ed3 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 10 May 2024 06:19:05 -0700 Subject: [PATCH 2/3] Some more tests --- Lib/test/test_typing.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3ee0d63f9f4372..81cfd001bc436f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -10241,6 +10241,12 @@ def test_constructor(self): def test_repr(self): self.assertEqual(repr(NoDefault), 'typing.NoDefault') + def test_doc(self): + self.assertIsInstance(NoDefault.__doc__, str) + + def test_class(self): + self.assertIs(NoDefault.__class__, type(NoDefault)) + def test_no_call(self): with self.assertRaises(TypeError): NoDefault() From 5695c229a895c298d08e9fd4d01ecfc5075feb42 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 10 May 2024 06:32:23 -0700 Subject: [PATCH 3/3] Feedback --- Lib/test/test_typing.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 81cfd001bc436f..81fea41e9b9823 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -45,7 +45,7 @@ import weakref import types -from test.support import captured_stderr, cpython_only, infinite_recursion +from test.support import captured_stderr, cpython_only, infinite_recursion, requires_docstrings from test.typinganndata import ann_module695, mod_generics_cache, _typed_dict_helper @@ -10241,6 +10241,7 @@ def test_constructor(self): def test_repr(self): self.assertEqual(repr(NoDefault), 'typing.NoDefault') + @requires_docstrings def test_doc(self): self.assertIsInstance(NoDefault.__doc__, str) @@ -10260,6 +10261,8 @@ def test_no_attributes(self): # TypeError is consistent with the behavior of NoneType with self.assertRaises(TypeError): type(NoDefault).foo = 3 + with self.assertRaises(AttributeError): + type(NoDefault).foo class AllTests(BaseTestCase):