From 13d7cf997bc9c22cf67c42fd799413e8325e0039 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 10 May 2024 08:42:00 -0700 Subject: [PATCH] gh-118895: Call PyType_Ready() on typing.NoDefault (#118897) --- Include/internal/pycore_typevarobject.h | 1 + Lib/test/test_typing.py | 23 +++++++++++++++++-- ...-05-10-05-24-32.gh-issue-118895.wUm5r2.rst | 2 ++ Modules/_typingmodule.c | 3 +++ 4 files changed, 27 insertions(+), 2 deletions(-) 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 80a2daf4efc..a368edebd62 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 8dde8aedd2a..81fea41e9b9 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 @@ -10236,15 +10236,34 @@ 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') + @requires_docstrings + 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() + 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 + with self.assertRaises(AttributeError): + type(NoDefault).foo + 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 00000000000..226c8d612a0 --- /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 09fbb3c5e8b..37af00f3071 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; }