Skip to content

Commit d0b664e

Browse files
gh-118168: Fix Unpack interaction with builtin aliases (#118169)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent d687d3f commit d0b664e

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

Lib/test/test_typing.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,38 @@ def foo(**kwargs: Unpack[Movie]): ...
978978
self.assertEqual(repr(foo.__annotations__['kwargs']),
979979
f"typing.Unpack[{__name__}.Movie]")
980980

981+
def test_builtin_tuple(self):
982+
Ts = TypeVarTuple("Ts")
983+
984+
class Old(Generic[*Ts]): ...
985+
class New[*Ts]: ...
986+
987+
PartOld = Old[int, *Ts]
988+
self.assertEqual(PartOld[str].__args__, (int, str))
989+
self.assertEqual(PartOld[*tuple[str]].__args__, (int, str))
990+
self.assertEqual(PartOld[*Tuple[str]].__args__, (int, str))
991+
self.assertEqual(PartOld[Unpack[tuple[str]]].__args__, (int, str))
992+
self.assertEqual(PartOld[Unpack[Tuple[str]]].__args__, (int, str))
993+
994+
PartNew = New[int, *Ts]
995+
self.assertEqual(PartNew[str].__args__, (int, str))
996+
self.assertEqual(PartNew[*tuple[str]].__args__, (int, str))
997+
self.assertEqual(PartNew[*Tuple[str]].__args__, (int, str))
998+
self.assertEqual(PartNew[Unpack[tuple[str]]].__args__, (int, str))
999+
self.assertEqual(PartNew[Unpack[Tuple[str]]].__args__, (int, str))
1000+
1001+
def test_unpack_wrong_type(self):
1002+
Ts = TypeVarTuple("Ts")
1003+
class Gen[*Ts]: ...
1004+
PartGen = Gen[int, *Ts]
1005+
1006+
bad_unpack_param = re.escape("Unpack[...] must be used with a tuple type")
1007+
with self.assertRaisesRegex(TypeError, bad_unpack_param):
1008+
PartGen[Unpack[list[int]]]
1009+
with self.assertRaisesRegex(TypeError, bad_unpack_param):
1010+
PartGen[Unpack[List[int]]]
1011+
1012+
9811013
class TypeVarTupleTests(BaseTestCase):
9821014

9831015
def assertEndsWith(self, string, tail):

Lib/typing.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,8 +1786,9 @@ def __typing_unpacked_tuple_args__(self):
17861786
assert self.__origin__ is Unpack
17871787
assert len(self.__args__) == 1
17881788
arg, = self.__args__
1789-
if isinstance(arg, _GenericAlias):
1790-
assert arg.__origin__ is tuple
1789+
if isinstance(arg, (_GenericAlias, types.GenericAlias)):
1790+
if arg.__origin__ is not tuple:
1791+
raise TypeError("Unpack[...] must be used with a tuple type")
17911792
return arg.__args__
17921793
return None
17931794

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix incorrect argument substitution when :data:`typing.Unpack` is used with
2+
the builtin :class:`tuple`. :data:`!typing.Unpack` now raises
3+
:exc:`TypeError` when used with certain invalid types. Patch by Jelle
4+
Zijlstra.

0 commit comments

Comments
 (0)