mirror of
https://github.com/python/cpython.git
synced 2025-08-03 08:34:29 +00:00
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
(cherry picked from commit e1abffca45
)
Co-authored-by: Gregory Beauregard <greg@greg.red>
This commit is contained in:
parent
367a37a18c
commit
41e0aead3d
3 changed files with 13 additions and 4 deletions
|
@ -4582,6 +4582,14 @@ class AnnotatedTests(BaseTestCase):
|
|||
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])
|
||||
|
|
|
@ -143,7 +143,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
|
||||
|
@ -156,7 +156,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,)
|
||||
|
@ -691,7 +691,7 @@ class ForwardRef(_Final, _root=True):
|
|||
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__}
|
||||
|
@ -1677,7 +1677,7 @@ class Annotated:
|
|||
"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)
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Allow :data:`typing.Annotated` to wrap :data:`typing.Final` and :data:`typing.ClassVar`. Patch by Gregory Beauregard.
|
Loading…
Add table
Add a link
Reference in a new issue