Skip to content

Commit ff79863

Browse files
committed
Merge remote-tracking branch 'upstream/main' into concatenate/ellipsis-support-110
2 parents 97bdfd1 + a2abfe6 commit ff79863

File tree

4 files changed

+68
-4
lines changed

4 files changed

+68
-4
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: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
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-
- Extended the Concatenate backport for Python 3.8-3.10 to now accept
20-
ellipsis as an argument. 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).
21+
- Extended the `Concatenate` backport for Python 3.8-3.10 to now accept
22+
`Ellipsis` as an argument. 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
@@ -5837,6 +5837,47 @@ class D(Protocol[T1, T2, Unpack[Ts]]): pass
58375837
with self.assertRaises(TypeError):
58385838
klass[int]
58395839

5840+
def test_substitution(self):
5841+
Ts = TypeVarTuple("Ts")
5842+
unpacked_str = Unpack[Ts][str] # This should not raise an error
5843+
self.assertIs(unpacked_str, str)
5844+
5845+
@skipUnless(TYPING_3_11_0, "Needs Issue #103 for <3.11")
5846+
def test_nested_unpack(self):
5847+
Ts = TypeVarTuple("Ts")
5848+
Variadic = Tuple[int, Unpack[Ts]]
5849+
# Tuple[int, int, Tuple[str, int]]
5850+
direct_subscription = Variadic[int, Tuple[str, int]]
5851+
# Tuple[int, int, Tuple[*Ts, int]]
5852+
TupleAliasTs = Variadic[int, Tuple[Unpack[Ts], int]]
5853+
5854+
# Tuple[int, int, Tuple[str, int]]
5855+
recursive_unpack = TupleAliasTs[str]
5856+
self.assertEqual(direct_subscription, recursive_unpack)
5857+
self.assertEqual(get_args(recursive_unpack), (int, int, Tuple[str, int]))
5858+
5859+
# Test with Callable
5860+
T = TypeVar("T")
5861+
# Tuple[int, (*Ts) -> T]
5862+
CallableAliasTsT = Variadic[Callable[[Unpack[Ts]], T]]
5863+
# Tuple[int, (str, int) -> object]
5864+
callable_fully_subscripted = CallableAliasTsT[Unpack[Tuple[str, int]], object]
5865+
self.assertEqual(get_args(callable_fully_subscripted), (int, Callable[[str, int], object]))
5866+
5867+
@skipUnless(TYPING_3_11_0, "Needs Issue #103 for <3.11")
5868+
def test_equivalent_nested_variadics(self):
5869+
T = TypeVar("T")
5870+
Ts = TypeVarTuple("Ts")
5871+
Variadic = Tuple[int, Unpack[Ts]]
5872+
TupleAliasTsT = Variadic[Tuple[Unpack[Ts], T]]
5873+
nested_tuple_bare = TupleAliasTsT[str, int, object]
5874+
5875+
self.assertEqual(get_args(nested_tuple_bare), (int, Tuple[str, int, object]))
5876+
# Variants
5877+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str, int, object]]])
5878+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str, int]], object])
5879+
self.assertEqual(nested_tuple_bare, TupleAliasTsT[Unpack[Tuple[str]], Unpack[Tuple[int]], object])
5880+
58405881

58415882
class TypeVarTupleTests(BaseTestCase):
58425883

src/typing_extensions.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,6 +2452,17 @@ def __typing_unpacked_tuple_args__(self):
24522452
return arg.__args__
24532453
return None
24542454

2455+
@property
2456+
def __typing_is_unpacked_typevartuple__(self):
2457+
assert self.__origin__ is Unpack
2458+
assert len(self.__args__) == 1
2459+
return isinstance(self.__args__[0], TypeVarTuple)
2460+
2461+
def __getitem__(self, args):
2462+
if self.__typing_is_unpacked_typevartuple__:
2463+
return args
2464+
return super().__getitem__(args)
2465+
24552466
@_UnpackSpecialForm
24562467
def Unpack(self, parameters):
24572468
item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
@@ -2464,6 +2475,17 @@ def _is_unpack(obj):
24642475
class _UnpackAlias(typing._GenericAlias, _root=True):
24652476
__class__ = typing.TypeVar
24662477

2478+
@property
2479+
def __typing_is_unpacked_typevartuple__(self):
2480+
assert self.__origin__ is Unpack
2481+
assert len(self.__args__) == 1
2482+
return isinstance(self.__args__[0], TypeVarTuple)
2483+
2484+
def __getitem__(self, args):
2485+
if self.__typing_is_unpacked_typevartuple__:
2486+
return args
2487+
return super().__getitem__(args)
2488+
24672489
class _UnpackForm(_ExtensionsSpecialForm, _root=True):
24682490
def __getitem__(self, parameters):
24692491
item = typing._type_check(parameters,

0 commit comments

Comments
 (0)