From 22235b4dae377f9120e86e071d17342b76996ce0 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 bc7f14f90a7cf9..db0501d70e3442 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -762,6 +762,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 03d5357d4cf51a..2ba128b3f225a9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1123,6 +1123,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 da0d060bf245ac6610617b4b0732687a5827053d 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 bb0ad9bd14b446df2ed949099fc51920d9dbe54a 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 2ba128b3f225a9..31c24865c13feb 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1124,7 +1124,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 120b9bb8e9cfc718528bbbabd444b5fda43153fd 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 1d35e9b6169f2d4c9a5d25783600ca7bdbefce98 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 31c24865c13feb..25234d2d707dd2 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1113,7 +1113,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. @@ -1123,8 +1123,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 bd6d90f0728482f4cf57eaa83b1d6c7564be7bb9 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.