Skip to content

Commit 30e25d4

Browse files
miss-islingtonJelleZijlstraAlexWaygood
authored
[3.12] gh-118168: Fix Unpack interaction with builtin aliases (GH-118169) (#118178)
Co-authored-by: Jelle Zijlstra <[email protected]> Co-authored-by: Alex Waygood <[email protected]>
1 parent fbe29e6 commit 30e25d4

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
@@ -979,6 +979,38 @@ def foo(**kwargs: Unpack[Movie]): ...
979979
self.assertEqual(repr(foo.__annotations__['kwargs']),
980980
f"typing.Unpack[{__name__}.Movie]")
981981

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

9841016
def assertEndsWith(self, string, tail):

Lib/typing.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,8 +1704,9 @@ def __typing_unpacked_tuple_args__(self):
17041704
assert self.__origin__ is Unpack
17051705
assert len(self.__args__) == 1
17061706
arg, = self.__args__
1707-
if isinstance(arg, _GenericAlias):
1708-
assert arg.__origin__ is tuple
1707+
if isinstance(arg, (_GenericAlias, types.GenericAlias)):
1708+
if arg.__origin__ is not tuple:
1709+
raise TypeError("Unpack[...] must be used with a tuple type")
17091710
return arg.__args__
17101711
return None
17111712

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)