Skip to content

Commit f2bc12f

Browse files
authoredApr 16, 2022
bpo-43224: Add tests for TypeVarTuple substitution in Annotated (GH-31846)
1 parent 468314c commit f2bc12f

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed
 

‎Lib/test/test_typing.py

+71
Original file line numberDiff line numberDiff line change
@@ -5873,6 +5873,77 @@ def test_subst(self):
58735873
with self.assertRaises(TypeError):
58745874
LI[None]
58755875

5876+
def test_typevar_subst(self):
5877+
dec = "a decoration"
5878+
Ts = TypeVarTuple('Ts')
5879+
T = TypeVar('T')
5880+
T1 = TypeVar('T1')
5881+
T2 = TypeVar('T2')
5882+
5883+
A = Annotated[Tuple[Unpack[Ts]], dec]
5884+
self.assertEqual(A[int], Annotated[Tuple[int], dec])
5885+
self.assertEqual(A[str, int], Annotated[Tuple[str, int], dec])
5886+
with self.assertRaises(TypeError):
5887+
Annotated[Unpack[Ts], dec]
5888+
5889+
B = Annotated[Tuple[T, Unpack[Ts]], dec]
5890+
self.assertEqual(B[int], Annotated[Tuple[int], dec])
5891+
self.assertEqual(B[int, str], Annotated[Tuple[int, str], dec])
5892+
self.assertEqual(
5893+
B[int, str, float],
5894+
Annotated[Tuple[int, str, float], dec]
5895+
)
5896+
with self.assertRaises(TypeError):
5897+
B[()]
5898+
5899+
C = Annotated[Tuple[Unpack[Ts], T], dec]
5900+
self.assertEqual(C[int], Annotated[Tuple[int], dec])
5901+
self.assertEqual(C[int, str], Annotated[Tuple[int, str], dec])
5902+
self.assertEqual(
5903+
C[int, str, float],
5904+
Annotated[Tuple[int, str, float], dec]
5905+
)
5906+
with self.assertRaises(TypeError):
5907+
C[()]
5908+
5909+
D = Annotated[Tuple[T1, Unpack[Ts], T2], dec]
5910+
self.assertEqual(D[int, str], Annotated[Tuple[int, str], dec])
5911+
self.assertEqual(
5912+
D[int, str, float],
5913+
Annotated[Tuple[int, str, float], dec]
5914+
)
5915+
self.assertEqual(
5916+
D[int, str, bool, float],
5917+
Annotated[Tuple[int, str, bool, float], dec]
5918+
)
5919+
with self.assertRaises(TypeError):
5920+
D[int]
5921+
5922+
# Now let's try creating an alias from an alias.
5923+
5924+
Ts2 = TypeVarTuple('Ts2')
5925+
T3 = TypeVar('T3')
5926+
T4 = TypeVar('T4')
5927+
5928+
E = D[T3, Unpack[Ts2], T4]
5929+
self.assertEqual(
5930+
E,
5931+
Annotated[Tuple[T3, Unpack[Ts2], T4], dec]
5932+
)
5933+
self.assertEqual(
5934+
E[int, str], Annotated[Tuple[int, str], dec]
5935+
)
5936+
self.assertEqual(
5937+
E[int, str, float],
5938+
Annotated[Tuple[int, str, float], dec]
5939+
)
5940+
self.assertEqual(
5941+
E[int, str, bool, float],
5942+
Annotated[Tuple[int, str, bool, float], dec]
5943+
)
5944+
with self.assertRaises(TypeError):
5945+
E[int]
5946+
58765947
def test_annotated_in_other_types(self):
58775948
X = List[Annotated[T, 5]]
58785949
self.assertEqual(X[int], List[Annotated[int, 5]])

‎Lib/typing.py

+14
Original file line numberDiff line numberDiff line change
@@ -2080,6 +2080,17 @@ class Annotated:
20802080
20812081
OptimizedList = Annotated[List[T], runtime.Optimize()]
20822082
OptimizedList[int] == Annotated[List[int], runtime.Optimize()]
2083+
2084+
- Annotated cannot be used with an unpacked TypeVarTuple::
2085+
2086+
Annotated[*Ts, Ann1] # NOT valid
2087+
2088+
This would be equivalent to
2089+
2090+
Annotated[T1, T2, T3, ..., Ann1]
2091+
2092+
where T1, T2 etc. are TypeVars, which would be invalid, because
2093+
only one type should be passed to Annotated.
20832094
"""
20842095

20852096
__slots__ = ()
@@ -2093,6 +2104,9 @@ def __class_getitem__(cls, params):
20932104
raise TypeError("Annotated[...] should be used "
20942105
"with at least two arguments (a type and an "
20952106
"annotation).")
2107+
if _is_unpacked_typevartuple(params[0]):
2108+
raise TypeError("Annotated[...] should not be used with an "
2109+
"unpacked TypeVarTuple")
20962110
msg = "Annotated[t, ...]: t must be a type."
20972111
origin = _type_check(params[0], msg, allow_special_forms=True)
20982112
metadata = tuple(params[1:])

0 commit comments

Comments
 (0)
Please sign in to comment.