8000 Fix subscription of Unpack causing nested Unpacks to not be resolved … · python/typing_extensions@a2abfe6 · GitHub
[go: up one dir, main page]

Skip to content

Commit a2abfe6

Browse files
Fix subscription of Unpack causing nested Unpacks to not be resolved correctly (#480)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
1 parent 7f4aef7 commit a2abfe6

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
subscripted objects) had wrong parameters if they were directly
1717
subscripted with an `Unpack` object.
1818
Patch by [Daraan](https://github.com/Daraan).
19+
- Fix error in subscription of `Unpack` aliases causing nested Unpacks
20+
to not be resolved correctly. Patch by [Daraan](https://github.com/Daraan).
1921

2022
# Release 4.12.2 (June 7, 2024)
2123

src/test_typing_extensions.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5779,6 +5779,47 @@ class D(Protocol[T1, T2, Unpack[Ts]]): pass
57795779
with self.assertRaises(TypeError):
57805780
klass[int]
57815781

5782+
def test_substitution(self):
5783+
Ts = TypeVarTuple("Ts")
5784+
unpacked_str = Unpack[Ts][str] # This should not raise an error
5785+
self.assertIs(unpacked_str, str)
5786+
5787+
@skipUnless(TYPING_3_11_0, "Needs Issue #103 for <3.11")
5788+
def test_nested_unpack(self):
5789+
Ts = TypeVarTuple("Ts")
5790+
Variadic = Tuple[int, Unpack[Ts]]
5791+
# Tuple[int, int, Tuple[str, int]]
5792+
direct_subscription = Variadic[int, Tuple[str, int]]
5793+
# Tuple[int, int, Tuple[*Ts, int]]
5794+
TupleAliasTs = Variadic[int, Tuple[Unpack[Ts], int]]
5795+
5796+
# Tuple[int, int, Tuple[str, int]]
5797+
recursive_unpack = TupleAliasTs[str]
5798+
self.assertEqual(direct_subscription, recursive_unpack)
5799+
self.assertEqual(get_args(recursive_unpack), (int, int, Tuple[str, int]))
5800+
5801+
# Test with Callable
5802+
T = TypeVar("T")
5803+
# Tuple[int, (*Ts) -> T]
5804+
CallableAliasTsT = Variadic[Callable[[Unpack[Ts]], T]]
5805+
# Tuple[int, (str, int) -> object]
5806+
callable_fully_subscripted = CallableAliasTsT[Unpack[Tuple[str, int]], object]
5807+
self.assertEqual(get_args(callable_fully_subscripted), (int, Callable[[str, int], object]))
5808+
5809+
@skipUnless(TYPING_3_11_0, "Needs Issue #103 for <3.11")
5810+
def test_equivalent_nested_variadics(self):
5811+
T = TypeVar("T")
5812+
Ts = TypeVarTuple("Ts")
5813+
Variadic = Tuple[int, Unpack[Ts]]
5814+
TupleAliasTsT = Variadic[Tuple[Unpack[Ts], T]]
5815+
nested_tuple_bare = TupleAliasTsT[str, int, object]
5816+
5817+
self.assertEqual(get_args(nested_tuple_bare), (int, Tuple[str, int, object]))
5818+
# Variants
5819+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str, int, object]]])
5820+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str, int]], object])
5821+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str]], Unpack[Tuple[int]], object])
5822+
57825823

57835824
class TypeVarTupleTests(BaseTestCase):
57845825

src/typing_extensions.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,6 +2424,17 @@ def __typing_unpacked_tuple_args__(self):
24242424
return arg.__args__
24252425
return None
24262426

2427+
@property
2428+
def __typing_is_unpacked_typevartuple__(self):
2429+
assert self.__origin__ is Unpack
2430+
assert len(self.__args__) == 1
2431+
return isinstance(self.__args__[0], TypeVarTuple)
2432+
2433+
def __getitem__(self, args):
2434+
if self.__typing_is_unpacked_typevartuple__:
2435+
return args
2436+
return super().__getitem__(args)
2437+
24272438
@_UnpackSpecialForm
24282439
def Unpack(self, parameters):
24292440
item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
@@ -2436,6 +2447,17 @@ def _is_unpack(obj):
24362447
class _UnpackAlias(typing._GenericAlias, _root=True):
24372448
__class__ = typing.TypeVar
24382449

2450+
@property
2451+
def __typing_is_unpacked_typevartuple__(self):
2452+
assert self.__origin__ is Unpack
2453+
assert len(self.__args__) == 1
2454+
return isinstance(self.__args__[0], TypeVarTuple)
2455+
2456+
def __getitem__(self, args):
2457+
if self.__typing_is_unpacked_typevartuple__:
2458+
return args
2459+
return super().__getitem__(args)
2460+
24392461
class _UnpackForm(_ExtensionsSpecialForm, _root=True):
24402462
def __getitem__(self, parameters):
24412463
item = typing._type_check(parameters,

0 commit comments

Comments
 (0)
0