[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>
This commit is contained in:
Miss Islington (bot) 2024-04-23 15:57:36 +02:00 committed by GitHub
parent fbe29e639d
commit 30e25d4ff9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 2 deletions

View file

@ -979,6 +979,38 @@ class UnpackTests(BaseTestCase):
self.assertEqual(repr(foo.__annotations__['kwargs']), self.assertEqual(repr(foo.__annotations__['kwargs']),
f"typing.Unpack[{__name__}.Movie]") 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): class TypeVarTupleTests(BaseTestCase):
def assertEndsWith(self, string, tail): def assertEndsWith(self, string, tail):

View file

@ -1704,8 +1704,9 @@ class _UnpackGenericAlias(_GenericAlias, _root=True):
assert self.__origin__ is Unpack assert self.__origin__ is Unpack
assert len(self.__args__) == 1 assert len(self.__args__) == 1
arg, = self.__args__ arg, = self.__args__
if isinstance(arg, _GenericAlias): if isinstance(arg, (_GenericAlias, types.GenericAlias)):
assert arg.__origin__ is tuple if arg.__origin__ is not tuple:
raise TypeError("Unpack[...] must be used with a tuple type")
return arg.__args__ return arg.__args__
return None return None

View file

@ -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.