]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-105509: Simplify implementation of `typing.Annotated` (#105510)
authorAlex Waygood <Alex.Waygood@Gmail.com>
Fri, 1 Sep 2023 20:57:25 +0000 (21:57 +0100)
committerGitHub <noreply@github.com>
Fri, 1 Sep 2023 20:57:25 +0000 (13:57 -0700)
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS.d/next/Library/2023-06-08-15-56-45.gh-issue-105509.YIG57j.rst [new file with mode: 0644]

index 6447ed6078e178cd60473b88f6798f1b517869af..69f5ff913c57bb9b6bc12ae620d475be03066408 100644 (file)
@@ -8189,8 +8189,7 @@ class AnnotatedTests(BaseTestCase):
 
     def test_new(self):
         with self.assertRaisesRegex(
-            TypeError,
-            'Type Annotated cannot be instantiated',
+            TypeError, 'Cannot instantiate typing.Annotated',
         ):
             Annotated()
 
index 387b4c5ad5284b74591e35e8b185c9864814d7f7..8655b756a9fd13e288c4744fc6878cd3e945f777 100644 (file)
@@ -2001,7 +2001,8 @@ class _AnnotatedAlias(_NotIterable, _GenericAlias, _root=True):
         return (self.__origin__,)
 
 
-class Annotated:
+@_SpecialForm
+def Annotated(self, params):
     """Add context-specific metadata to a type.
 
     Example: Annotated[int, runtime_check.Unsigned] indicates to the
@@ -2048,30 +2049,17 @@ class Annotated:
       where T1, T2 etc. are TypeVars, which would be invalid, because
       only one type should be passed to Annotated.
     """
-
-    __slots__ = ()
-
-    def __new__(cls, *args, **kwargs):
-        raise TypeError("Type Annotated cannot be instantiated.")
-
-    @_tp_cache
-    def __class_getitem__(cls, params):
-        if not isinstance(params, tuple) or len(params) < 2:
-            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:])
-        return _AnnotatedAlias(origin, metadata)
-
-    def __init_subclass__(cls, *args, **kwargs):
-        raise TypeError(
-            "Cannot subclass {}.Annotated".format(cls.__module__)
-        )
+    if not isinstance(params, tuple) or len(params) < 2:
+        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:])
+    return _AnnotatedAlias(origin, metadata)
 
 
 def runtime_checkable(cls):
diff --git a/Misc/NEWS.d/next/Library/2023-06-08-15-56-45.gh-issue-105509.YIG57j.rst b/Misc/NEWS.d/next/Library/2023-06-08-15-56-45.gh-issue-105509.YIG57j.rst
new file mode 100644 (file)
index 0000000..26d8a66
--- /dev/null
@@ -0,0 +1,3 @@
+:data:`typing.Annotated` is now implemented as an instance of
+``typing._SpecialForm`` rather than a class. This should have no user-facing
+impact for users of the :mod:`typing` module public API.