[Python-checkins] bpo-46491: Allow Annotated on outside of Final/ClassVar (GH-30864)
miss-islington
webhook-mailer at python.org
Tue Jan 25 01:37:38 EST 2022
https://github.com/python/cpython/commit/e1abffca45b60729c460e3e2ad50c8c1946cfd4e
commit: e1abffca45b60729c460e3e2ad50c8c1946cfd4e
branch: main
author: Gregory Beauregard <greg at greg.red>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-01-24T22:37:15-08:00
summary:
bpo-46491: Allow Annotated on outside of Final/ClassVar (GH-30864)
We treat Annotated type arg as class-level annotation. This exempts it from checks against Final and ClassVar in order to allow using them in any nesting order.
Automerge-Triggered-By: GH:gvanrossum
files:
A Misc/NEWS.d/next/Library/2022-01-24-23-55-30.bpo-46491.jmIKHo.rst
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 150d7c081c30b..5777656552d79 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -4679,6 +4679,14 @@ class C:
A.x = 5
self.assertEqual(C.x, 5)
+ def test_special_form_containment(self):
+ class C:
+ classvar: Annotated[ClassVar[int], "a decoration"] = 4
+ const: Annotated[Final[int], "Const"] = 4
+
+ self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int])
+ self.assertEqual(get_type_hints(C, globals())['const'], Final[int])
+
def test_hash_eq(self):
self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
diff --git a/Lib/typing.py b/Lib/typing.py
index 7ff546fbb6492..e3e098b1fcc8f 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -151,7 +151,7 @@ def _type_convert(arg, module=None):
return arg
-def _type_check(arg, msg, is_argument=True, module=None, *, is_class=False):
+def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=False):
"""Check that the argument is a type, and return it (internal helper).
As a special case, accept None and return type(None) instead. Also wrap strings
@@ -164,7 +164,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, is_class=False):
We append the repr() of the actual value (truncated to 100 chars).
"""
invalid_generic_forms = (Generic, Protocol)
- if not is_class:
+ if not allow_special_forms:
invalid_generic_forms += (ClassVar,)
if is_argument:
invalid_generic_forms += (Final,)
@@ -697,7 +697,7 @@ def _evaluate(self, globalns, localns, recursive_guard):
eval(self.__forward_code__, globalns, localns),
"Forward references must evaluate to types.",
is_argument=self.__forward_is_argument__,
- is_class=self.__forward_is_class__,
+ allow_special_forms=self.__forward_is_class__,
)
self.__forward_value__ = _eval_type(
type_, globalns, localns, recursive_guard | {self.__forward_arg__}
@@ -1674,7 +1674,7 @@ def __class_getitem__(cls, params):
"with at least two arguments (a type and an "
"annotation).")
msg = "Annotated[t, ...]: t must be a type."
- origin = _type_check(params[0], msg)
+ origin = _type_check(params[0], msg, allow_special_forms=True)
metadata = tuple(params[1:])
return _AnnotatedAlias(origin, metadata)
diff --git a/Misc/NEWS.d/next/Library/2022-01-24-23-55-30.bpo-46491.jmIKHo.rst b/Misc/NEWS.d/next/Library/2022-01-24-23-55-30.bpo-46491.jmIKHo.rst
new file mode 100644
index 0000000000000..f66e8868f753f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-01-24-23-55-30.bpo-46491.jmIKHo.rst
@@ -0,0 +1 @@
+Allow :data:`typing.Annotated` to wrap :data:`typing.Final` and :data:`typing.ClassVar`. Patch by Gregory Beauregard.
More information about the Python-checkins
mailing list