Skip to content

Commit

Permalink
pythongh-118168: Fix Unpack interaction with builtin aliases (python#…
Browse files Browse the repository at this point in the history
…118169)

Co-authored-by: Alex Waygood <[email protected]>
  • Loading branch information
JelleZijlstra and AlexWaygood authored Apr 23, 2024
1 parent d687d3f commit d0b664e
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
32 changes: 32 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,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):
Expand Down
5 changes: 3 additions & 2 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1786,8 +1786,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

Expand Down
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit d0b664e

Please sign in to comment.