From 1a325455ea03aa3fc635eb0ab75253f516305429 Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Mon, 15 Dec 2025 22:54:37 +0800 Subject: [PATCH 1/4] Normalize ParamSpec __bound__ when bound is None When creating a ParamSpec with bound=None, the runtime __bound__ attribute is set to instead of None. This change mirrors TypeVar.__new__ by explicitly converting Py_None to NULL before type checking, restoring the correct semantics and ensuring consistency between TypeVar and ParamSpec. Signed-off-by: Yongtao Huang --- Objects/typevarobject.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 8e43962c7e37f4..f4734b2a745da3 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1337,6 +1337,9 @@ paramspec_new_impl(PyTypeObject *type, PyObject *name, PyObject *bound, PyErr_SetString(PyExc_ValueError, "Variance cannot be specified with infer_variance."); return NULL; } + if (Py_IsNone(bound)) { + bound = NULL; + } if (bound != NULL) { bound = type_check(bound, "Bound must be a type."); if (bound == NULL) { From 5afc57693fd5fdb7ac086849d28ac3f37eaad5c4 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 01:28:40 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-12-16-01-28-39.gh-issue-142750.9Nlo5U.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-16-01-28-39.gh-issue-142750.9Nlo5U.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-16-01-28-39.gh-issue-142750.9Nlo5U.rst b/Misc/NEWS.d/next/Library/2025-12-16-01-28-39.gh-issue-142750.9Nlo5U.rst new file mode 100644 index 00000000000000..481bdddbd0e3c2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-16-01-28-39.gh-issue-142750.9Nlo5U.rst @@ -0,0 +1 @@ +Fix ``typing.ParamSpec(..., bound=None)`` so that ``__bound__`` is ``None`` instead of ``NoneType``. From 0a427ec0722b4d647daa19d16a6381cd649052e1 Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Tue, 16 Dec 2025 09:36:49 +0800 Subject: [PATCH 3/4] Add unit test --- 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 e896df518447c5..785f87260c7cbb 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -10029,6 +10029,12 @@ def test_basic_with_exec(self): self.assertEqual(P.__name__, 'P') self.assertIs(P.__module__, None) + def test_bound(self): + P1 = ParamSpec("P1") + P2 = ParamSpec("P2", bound=None) + self.assertIs(P1.__bound__, None) + self.assertIs(P2.__bound__, None) + def test_valid_uses(self): P = ParamSpec('P') T = TypeVar('T') From d4cde947216b8758fb7cd8eb7b4de1c1b947a7ba Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Tue, 16 Dec 2025 09:51:36 +0800 Subject: [PATCH 4/4] Post fix --- Lib/test/test_typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 785f87260c7cbb..48883d0f7f66fb 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -10030,7 +10030,7 @@ def test_basic_with_exec(self): self.assertIs(P.__module__, None) def test_bound(self): - P1 = ParamSpec("P1") + P1 = ParamSpec("P1") P2 = ParamSpec("P2", bound=None) self.assertIs(P1.__bound__, None) self.assertIs(P2.__bound__, None)