diff options
author | Matthew Rahtz <matthew.rahtz@gmail.com> | 2022-04-16 04:24:28 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-16 04:24:28 (GMT) |
commit | f2bc12f0d5297899b57f3fa688b24f3c1d1bee7b (patch) | |
tree | d0d8734dd9ab6258a8997b809fa05cb60d9f9c4d /Lib | |
parent | 468314cc8bfdb6fd328cbbbb7d0807728f25e043 (diff) | |
download | cpython-f2bc12f0d5297899b57f3fa688b24f3c1d1bee7b.zip cpython-f2bc12f0d5297899b57f3fa688b24f3c1d1bee7b.tar.gz cpython-f2bc12f0d5297899b57f3fa688b24f3c1d1bee7b.tar.bz2 |
bpo-43224: Add tests for TypeVarTuple substitution in Annotated (GH-31846)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_typing.py | 71 | ||||
-rw-r--r-- | Lib/typing.py | 14 |
2 files changed, 85 insertions, 0 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 97fc66a..ffd0592 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -5873,6 +5873,77 @@ class AnnotatedTests(BaseTestCase): with self.assertRaises(TypeError): LI[None] + def test_typevar_subst(self): + dec = "a decoration" + Ts = TypeVarTuple('Ts') + T = TypeVar('T') + T1 = TypeVar('T1') + T2 = TypeVar('T2') + + A = Annotated[Tuple[Unpack[Ts]], dec] + self.assertEqual(A[int], Annotated[Tuple[int], dec]) + self.assertEqual(A[str, int], Annotated[Tuple[str, int], dec]) + with self.assertRaises(TypeError): + Annotated[Unpack[Ts], dec] + + B = Annotated[Tuple[T, Unpack[Ts]], dec] + self.assertEqual(B[int], Annotated[Tuple[int], dec]) + self.assertEqual(B[int, str], Annotated[Tuple[int, str], dec]) + self.assertEqual( + B[int, str, float], + Annotated[Tuple[int, str, float], dec] + ) + with self.assertRaises(TypeError): + B[()] + + C = Annotated[Tuple[Unpack[Ts], T], dec] + self.assertEqual(C[int], Annotated[Tuple[int], dec]) + self.assertEqual(C[int, str], Annotated[Tuple[int, str], dec]) + self.assertEqual( + C[int, str, float], + Annotated[Tuple[int, str, float], dec] + ) + with self.assertRaises(TypeError): + C[()] + + D = Annotated[Tuple[T1, Unpack[Ts], T2], dec] + self.assertEqual(D[int, str], Annotated[Tuple[int, str], dec]) + self.assertEqual( + D[int, str, float], + Annotated[Tuple[int, str, float], dec] + ) + self.assertEqual( + D[int, str, bool, float], + Annotated[Tuple[int, str, bool, float], dec] + ) + with self.assertRaises(TypeError): + D[int] + + # Now let's try creating an alias from an alias. + + Ts2 = TypeVarTuple('Ts2') + T3 = TypeVar('T3') + T4 = TypeVar('T4') + + E = D[T3, Unpack[Ts2], T4] + self.assertEqual( + E, + Annotated[Tuple[T3, Unpack[Ts2], T4], dec] + ) + self.assertEqual( + E[int, str], Annotated[Tuple[int, str], dec] + ) + self.assertEqual( + E[int, str, float], + Annotated[Tuple[int, str, float], dec] + ) + self.assertEqual( + E[int, str, bool, float], + Annotated[Tuple[int, str, bool, float], dec] + ) + with self.assertRaises(TypeError): + E[int] + def test_annotated_in_other_types(self): X = List[Annotated[T, 5]] self.assertEqual(X[int], List[Annotated[int, 5]]) diff --git a/Lib/typing.py b/Lib/typing.py index 1b584be..b26adc6 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2080,6 +2080,17 @@ class Annotated: OptimizedList = Annotated[List[T], runtime.Optimize()] OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + + - Annotated cannot be used with an unpacked TypeVarTuple:: + + Annotated[*Ts, Ann1] # NOT valid + + This would be equivalent to + + Annotated[T1, T2, T3, ..., Ann1] + + where T1, T2 etc. are TypeVars, which would be invalid, because + only one type should be passed to Annotated. """ __slots__ = () @@ -2093,6 +2104,9 @@ class Annotated: raise TypeError("Annotated[...] should be used " "with at least two arguments (a type and an " "annotation).") + if _is_unpacked_typevartuple(params[0]): + raise TypeError("Annotated[...] should not be used with an " + "unpacked TypeVarTuple") msg = "Annotated[t, ...]: t must be a type." origin = _type_check(params[0], msg, allow_special_forms=True) metadata = tuple(params[1:]) |