Skip to content

Commit b92d72f

Browse files
Merge branch 'main' into concatenate/ellipsis-3.10-v2
2 parents 858d9b3 + a2abfe6 commit b92d72f

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

.github/workflows/third_party.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ jobs:
137137
strategy:
138138
fail-fast: false
139139
matrix:
140-
# 3.13 support is pending
141-
python-version: ["3.9", "3.10", "3.11", "3.12"]
140+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
142141
runs-on: ubuntu-latest
143142
timeout-minutes: 60
144143
steps:

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
Patch by [Daraan](https://github.com/Daraan).
1919
- Backport to Python 3.10 to support substitution with `...` on `Callable`
2020
aliases that have a `Concatenate` argument. Patch by [Daraan](https://github.com/Daraan).
21+
- Fix error in subscription of `Unpack` aliases causing nested Unpacks
22+
to not be resolved correctly. Patch by [Daraan](https://github.com/Daraan).
2123

2224
# Release 4.12.2 (June 7, 2024)
2325

src/test_typing_extensions.py

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

5794+
def test_substitution(self):
5795+
Ts = TypeVarTuple("Ts")
5796+
unpacked_str = Unpack[Ts][str] # This should not raise an error
5797+
self.assertIs(unpacked_str, str)
5798+
5799+
@skipUnless(TYPING_3_11_0, "Needs Issue #103 for <3.11")
5800+
def test_nested_unpack(self):
5801+
Ts = TypeVarTuple("Ts")
5802+
Variadic = Tuple[int, Unpack[Ts]]
5803+
# Tuple[int, int, Tuple[str, int]]
5804+
direct_subscription = Variadic[int, Tuple[str, int]]
5805+
# Tuple[int, int, Tuple[*Ts, int]]
5806+
TupleAliasTs = Variadic[int, Tuple[Unpack[Ts], int]]
5807+
5808+
# Tuple[int, int, Tuple[str, int]]
5809+
recursive_unpack = TupleAliasTs[str]
5810+
self.assertEqual(direct_subscription, recursive_unpack)
5811+
self.assertEqual(get_args(recursive_unpack), (int, int, Tuple[str, int]))
5812+
5813+
# Test with Callable
5814+
T = TypeVar("T")
5815+
# Tuple[int, (*Ts) -> T]
5816+
CallableAliasTsT = Variadic[Callable[[Unpack[Ts]], T]]
5817+
# Tuple[int, (str, int) -> object]
5818+
callable_fully_subscripted = CallableAliasTsT[Unpack[Tuple[str, int]], object]
5819+
self.assertEqual(get_args(callable_fully_subscripted), (int, Callable[[str, int], object]))
5820+
5821+
@skipUnless(TYPING_3_11_0, "Needs Issue #103 for <3.11")
5822+
def test_equivalent_nested_variadics(self):
5823+
T = TypeVar("T")
5824+
Ts = TypeVarTuple("Ts")
5825+
Variadic = Tuple[int, Unpack[Ts]]
5826+
TupleAliasTsT = Variadic[Tuple[Unpack[Ts], T]]
5827+
nested_tuple_bare = TupleAliasTsT[str, int, object]
5828+
5829+
self.assertEqual(get_args(nested_tuple_bare), (int, Tuple[str, int, object]))
5830+
# Variants
5831+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str, int, object]]])
5832+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str, int]], object])
5833+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str]], Unpack[Tuple[int]], object])
5834+
57945835

57955836
class TypeVarTupleTests(BaseTestCase):
57965837

src/typing_extensions.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2448,6 +2448,17 @@ def __typing_unpacked_tuple_args__(self):
24482448
return arg.__args__
24492449
return None
24502450

2451+
@property
2452+
def __typing_is_unpacked_typevartuple__(self):
2453+
assert self.__origin__ is Unpack
2454+
assert len(self.__args__) == 1
2455+
return isinstance(self.__args__[0], TypeVarTuple)
2456+
2457+
def __getitem__(self, args):
2458+
if self.__typing_is_unpacked_typevartuple__:
2459+
return args
2460+
return super().__getitem__(args)
2461+
24512462
@_UnpackSpecialForm
24522463
def Unpack(self, parameters):
24532464
item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
@@ -2460,6 +2471,17 @@ def _is_unpack(obj):
24602471
class _UnpackAlias(typing._GenericAlias, _root=True):
24612472
__class__ = typing.TypeVar
24622473

2474+
@property
2475+
def __typing_is_unpacked_typevartuple__(self):
2476+
assert self.__origin__ is Unpack
2477+
assert len(self.__args__) == 1
2478+
return isinstance(self.__args__[0], TypeVarTuple)
2479+
2480+
def __getitem__(self, args):
2481+
if self.__typing_is_unpacked_typevartuple__:
2482+
return args
2483+
return super().__getitem__(args)
2484+
24632485
class _UnpackForm(_ExtensionsSpecialForm, _root=True):
24642486
def __getitem__(self, parameters):
24652487
item = typing._type_check(parameters,

0 commit comments

Comments
 (0)