]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-118168: Fix Unpack interaction with builtin aliases (GH-118169) (#118178)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 23 Apr 2024 13:57:36 +0000 (15:57 +0200)
committerGitHub <noreply@github.com>
Tue, 23 Apr 2024 13:57:36 +0000 (13:57 +0000)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS.d/next/Library/2024-04-22-20-42-29.gh-issue-118168.Igni7h.rst [new file with mode: 0644]

index e7cb01ac903d1162544c5f43aa56af3695023974..ffb1425e1f32a88170fd85295296af4cce4608b2 100644 (file)
@@ -979,6 +979,38 @@ class UnpackTests(BaseTestCase):
         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):
index 82d05f4caec26dc40371221669d857f58e4ebe82..9e39ffe906785067775457d62dc0961a539601d8 100644 (file)
@@ -1704,8 +1704,9 @@ class _UnpackGenericAlias(_GenericAlias, _root=True):
         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 (file)
index 0000000..78c3e0f
--- /dev/null
@@ -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.