Skip to content

Commit ced5005

Browse files
authored
bpo-46539: Pass status of special typeforms to forward references (GH-30926)
Previously this didn't matter because there weren't any valid code paths that could trigger a type check with a special form, but after the bug fix for `Annotated` wrapping special forms it's now possible to annotate something like `Annotated['ClassVar[int]', (3, 4)]`. This change would also be needed for proposed future changes, such as allowing `ClassVar` and `Final` to nest each other in dataclasses.
1 parent 6b491b9 commit ced5005

File tree

3 files changed

+18
-3
lines changed

3 files changed

+18
-3
lines changed

Lib/test/test_typing.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2870,6 +2870,20 @@ def foo(a: 'Callable[..., T]'):
28702870
self.assertEqual(get_type_hints(foo, globals(), locals()),
28712871
{'a': Callable[..., T]})
28722872

2873+
def test_special_forms_forward(self):
2874+
2875+
class C:
2876+
a: Annotated['ClassVar[int]', (3, 5)] = 4
2877+
b: Annotated['Final[int]', "const"] = 4
2878+
2879+
class CF:
2880+
b: List['Final[int]'] = 4
2881+
2882+
self.assertEqual(get_type_hints(C, globals())['a'], ClassVar[int])
2883+
self.assertEqual(get_type_hints(C, globals())['b'], Final[int])
2884+
with self.assertRaises(TypeError):
2885+
get_type_hints(CF, globals()),
2886+
28732887
def test_syntax_error(self):
28742888

28752889
with self.assertRaises(SyntaxError):

Lib/typing.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,12 @@ def _idfunc(_, x):
142142
# legitimate imports of those modules.
143143

144144

145-
def _type_convert(arg, module=None):
145+
def _type_convert(arg, module=None, *, allow_special_forms=False):
146146
"""For converting None to type(None), and strings to ForwardRef."""
147147
if arg is None:
148148
return type(None)
149149
if isinstance(arg, str):
150-
return ForwardRef(arg, module=module)
150+
return ForwardRef(arg, module=module, is_class=allow_special_forms)
151151
return arg
152152

153153

@@ -169,7 +169,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=
169169
if is_argument:
170170
invalid_generic_forms += (Final,)
171171

172-
arg = _type_convert(arg, module=module)
172+
arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms)
173173
if (isinstance(arg, _GenericAlias) and
174174
arg.__origin__ in invalid_generic_forms):
175175
raise TypeError(f"{arg} is not valid as type argument")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
In :func:`typing.get_type_hints`, support evaluating stringified ``ClassVar`` and ``Final`` annotations inside ``Annotated``. Patch by Gregory Beauregard.

0 commit comments

Comments
 (0)