[Python-checkins] bpo-43224: Add tests for TypeVarTuple substitution in Annotated (GH-31846)

JelleZijlstra webhook-mailer at python.org
Sat Apr 16 00:24:34 EDT 2022


https://github.com/python/cpython/commit/f2bc12f0d5297899b57f3fa688b24f3c1d1bee7b
commit: f2bc12f0d5297899b57f3fa688b24f3c1d1bee7b
branch: main
author: Matthew Rahtz <matthew.rahtz at gmail.com>
committer: JelleZijlstra <jelle.zijlstra at gmail.com>
date: 2022-04-15T21:24:28-07:00
summary:

bpo-43224: Add tests for TypeVarTuple substitution in Annotated (GH-31846)

files:
M Lib/test/test_typing.py
M Lib/typing.py

diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 97fc66a2f748f..ffd0592a3b414 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -5873,6 +5873,77 @@ def test_subst(self):
         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 1b584bea0c3e5..b26adc63cc136 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 @@ def __class_getitem__(cls, params):
             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:])



More information about the Python-checkins mailing list