From deffc89255f7f049101d1da496af1f70cfc2c324 Mon Sep 17 00:00:00 2001 From: Xiaoming Wang Date: Sat, 13 Sep 2025 23:35:16 +1200 Subject: [PATCH 1/6] pythongh-138859: Account for `ParamSpec` defaults that are not lists when converting type argument list to tuple --- Lib/test/test_typing.py | 10 ++++++++++ Lib/typing.py | 2 ++ 2 files changed, 12 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 8238c62f0715f8..b754703bd7a772 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -761,6 +761,16 @@ class A(Generic[T, P, U]): ... self.assertEqual(A[float, [range]].__args__, (float, (range,), float)) self.assertEqual(A[float, [range], int].__args__, (float, (range,), int)) + def test_paramspec_and_typevar_specialization_2(self): + T = TypeVar("T") + P = ParamSpec('P', default=...) + U = TypeVar("U", default=float) + self.assertEqual(P.__default__, ...) + class A(Generic[T, P, U]): ... + self.assertEqual(A[float].__args__, (float, ..., float)) + self.assertEqual(A[float, [range]].__args__, (float, (range,), float)) + self.assertEqual(A[float, [range], int].__args__, (float, (range,), int)) + def test_typevartuple_none(self): U = TypeVarTuple('U') U_None = TypeVarTuple('U_None', default=None) diff --git a/Lib/typing.py b/Lib/typing.py index babe3c44d9dc55..b2f7fcaa265adb 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1110,6 +1110,8 @@ def _paramspec_prepare_subst(self, alias, args): # Convert lists to tuples to help other libraries cache the results. elif isinstance(args[i], list): args = (*args[:i], tuple(args[i]), *args[i+1:]) + else: + args = (*args[:i], args[i], *args[i + 1:]) return args From 4477f79a5d1e2611f16a1c8d1315289e8f94b56b Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:19:18 +0000 Subject: [PATCH 2/6] =?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-09-13-12-19-17.gh-issue-138859.PxjIoN.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst diff --git a/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst b/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst new file mode 100644 index 00000000000000..8b7ddb7ed8388a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst @@ -0,0 +1 @@ +Fix failure during parameterization of generics when a non-type-list `ParamSpec` default is followed by another type variable default, and the `ParamSpec` is not provided as a type argument. From 0e9588e653779687929a29a2add7d6c7e25c661b Mon Sep 17 00:00:00 2001 From: Xiaoming Wang Date: Sun, 14 Sep 2025 00:33:59 +1200 Subject: [PATCH 3/6] Address code review --- Lib/typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/typing.py b/Lib/typing.py index b2f7fcaa265adb..84522153a98e08 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1111,7 +1111,7 @@ def _paramspec_prepare_subst(self, alias, args): elif isinstance(args[i], list): args = (*args[:i], tuple(args[i]), *args[i+1:]) else: - args = (*args[:i], args[i], *args[i + 1:]) + args = tuple(args) return args From 4bd37c0276f07f7f57f65e01a046f91a3e0a82a0 Mon Sep 17 00:00:00 2001 From: Xiaoming Wang Date: Sun, 14 Sep 2025 00:35:28 +1200 Subject: [PATCH 4/6] Fix news entry --- .../next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst b/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst index 8b7ddb7ed8388a..c9ca121d2211ba 100644 --- a/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst +++ b/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst @@ -1 +1 @@ -Fix failure during parameterization of generics when a non-type-list `ParamSpec` default is followed by another type variable default, and the `ParamSpec` is not provided as a type argument. +Fix failure during parameterization of generics when a non-type-list ``ParamSpec`` default is followed by another type variable default, and the ``ParamSpec`` is not provided as a type argument. From da8416990dce1cc7c1dd322279a6a3c7f3914bfc Mon Sep 17 00:00:00 2001 From: Xiaoming Wang Date: Mon, 15 Sep 2025 14:04:00 +1200 Subject: [PATCH 5/6] Simplify args tuple creation --- Lib/typing.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index 84522153a98e08..5b76a5ef3aa6f0 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1100,7 +1100,7 @@ def _paramspec_prepare_subst(self, alias, args): params = alias.__parameters__ i = params.index(self) if i == len(args) and self.has_default(): - args = [*args, self.__default__] + args = (*args, self.__default__) if i >= len(args): raise TypeError(f"Too few arguments for {alias}") # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. @@ -1110,8 +1110,6 @@ def _paramspec_prepare_subst(self, alias, args): # Convert lists to tuples to help other libraries cache the results. elif isinstance(args[i], list): args = (*args[:i], tuple(args[i]), *args[i+1:]) - else: - args = tuple(args) return args From 9669479b26beae3eb75bca6e358138ad40e367c7 Mon Sep 17 00:00:00 2001 From: Xiaoming Wang Date: Tue, 16 Sep 2025 07:22:30 +1200 Subject: [PATCH 6/6] Reword news entry --- .../next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst b/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst index c9ca121d2211ba..a5d4dd042fcd5b 100644 --- a/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst +++ b/Misc/NEWS.d/next/Library/2025-09-13-12-19-17.gh-issue-138859.PxjIoN.rst @@ -1 +1 @@ -Fix failure during parameterization of generics when a non-type-list ``ParamSpec`` default is followed by another type variable default, and the ``ParamSpec`` is not provided as a type argument. +Fix generic type parameterization raising a :exc:`TypeError` when omitting a :class:`ParamSpec` that has a default which is not a list of types.