Mailing List Archive

[3.12] gh-118168: Fix Unpack interaction with builtin aliases (GH-118169) (#118178)
https://github.com/python/cpython/commit/30e25d4ff9e4adcbeb775b2125196017d0d19b23
commit: 30e25d4ff9e4adcbeb775b2125196017d0d19b23
branch: 3.12
author: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
committer: AlexWaygood <Alex.Waygood@Gmail.com>
date: 2024-04-23T13:57:36Z
summary:

[3.12] gh-118168: Fix Unpack interaction with builtin aliases (GH-118169) (#118178)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>

files:
A Misc/NEWS.d/next/Library/2024-04-22-20-42-29.gh-issue-118168.Igni7h.rst
M Lib/test/test_typing.py
M Lib/typing.py

diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index e7cb01ac903d11..ffb1425e1f32a8 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -979,6 +979,38 @@ def foo(**kwargs: Unpack[Movie]): ...
self.assertEqual(repr(foo.__annotations__['kwargs']),
f"typing.Unpack[{__name__}.Movie]")

+ def test_builtin_tuple(self):
+ Ts = TypeVarTuple("Ts")
+
+ class Old(Generic[*Ts]): ...
+ class New[*Ts]: ...
+
+ PartOld = Old[int, *Ts]
+ self.assertEqual(PartOld[str].__args__, (int, str))
+ self.assertEqual(PartOld[*tuple[str]].__args__, (int, str))
+ self.assertEqual(PartOld[*Tuple[str]].__args__, (int, str))
+ self.assertEqual(PartOld[Unpack[tuple[str]]].__args__, (int, str))
+ self.assertEqual(PartOld[Unpack[Tuple[str]]].__args__, (int, str))
+
+ PartNew = New[int, *Ts]
+ self.assertEqual(PartNew[str].__args__, (int, str))
+ self.assertEqual(PartNew[*tuple[str]].__args__, (int, str))
+ self.assertEqual(PartNew[*Tuple[str]].__args__, (int, str))
+ self.assertEqual(PartNew[Unpack[tuple[str]]].__args__, (int, str))
+ self.assertEqual(PartNew[Unpack[Tuple[str]]].__args__, (int, str))
+
+ def test_unpack_wrong_type(self):
+ Ts = TypeVarTuple("Ts")
+ class Gen[*Ts]: ...
+ PartGen = Gen[int, *Ts]
+
+ bad_unpack_param = re.escape("Unpack[...] must be used with a tuple type")
+ with self.assertRaisesRegex(TypeError, bad_unpack_param):
+ PartGen[Unpack[list[int]]]
+ with self.assertRaisesRegex(TypeError, bad_unpack_param):
+ PartGen[Unpack[List[int]]]
+
+
class TypeVarTupleTests(BaseTestCase):

def assertEndsWith(self, string, tail):
diff --git a/Lib/typing.py b/Lib/typing.py
index 82d05f4caec26d..9e39ffe9067850 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1704,8 +1704,9 @@ def __typing_unpacked_tuple_args__(self):
assert self.__origin__ is Unpack
assert len(self.__args__) == 1
arg, = self.__args__
- if isinstance(arg, _GenericAlias):
- assert arg.__origin__ is tuple
+ if isinstance(arg, (_GenericAlias, types.GenericAlias)):
+ if arg.__origin__ is not tuple:
+ raise TypeError("Unpack[...] must be used with a tuple type")
return arg.__args__
return None

diff --git a/Misc/NEWS.d/next/Library/2024-04-22-20-42-29.gh-issue-118168.Igni7h.rst b/Misc/NEWS.d/next/Library/2024-04-22-20-42-29.gh-issue-118168.Igni7h.rst
new file mode 100644
index 00000000000000..78c3e0fe17979a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-04-22-20-42-29.gh-issue-118168.Igni7h.rst
@@ -0,0 +1,4 @@
+Fix incorrect argument substitution when :data:`typing.Unpack` is used with
+the builtin :class:`tuple`. :data:`!typing.Unpack` now raises
+:exc:`TypeError` when used with certain invalid types. Patch by Jelle
+Zijlstra.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-leave@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: list-python-checkins@lists.gossamer-threads.com