From c0c0dfa19444eca81f062aa8ffb6ad0bbeeaab6c Mon Sep 17 00:00:00 2001 From: Gregory Beauregard Date: Wed, 26 Jan 2022 19:11:51 -0800 Subject: [PATCH] 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. (cherry picked from commit ced50051bb752a7c1e616f4b0c001f37f0354f32) Co-authored-by: Gregory Beauregard --- Lib/test/test_typing.py | 14 ++++++++++++++ Lib/typing.py | 6 +++--- .../2022-01-26-20-36-30.bpo-46539.23iW1d.rst | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-01-26-20-36-30.bpo-46539.23iW1d.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f70311c95b24e4..dfca96b9099322 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2623,6 +2623,20 @@ def foo(a: 'Callable[..., T]'): self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': Callable[..., T]}) + def test_special_forms_forward(self): + + class C: + a: Annotated['ClassVar[int]', (3, 5)] = 4 + b: Annotated['Final[int]', "const"] = 4 + + class CF: + b: List['Final[int]'] = 4 + + self.assertEqual(get_type_hints(C, globals())['a'], ClassVar[int]) + self.assertEqual(get_type_hints(C, globals())['b'], Final[int]) + with self.assertRaises(TypeError): + get_type_hints(CF, globals()), + def test_syntax_error(self): with self.assertRaises(SyntaxError): diff --git a/Lib/typing.py b/Lib/typing.py index fdc0f163d65043..18b21e96435b32 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -125,12 +125,12 @@ # legitimate imports of those modules. -def _type_convert(arg, module=None): +def _type_convert(arg, module=None, *, allow_special_forms=False): """For converting None to type(None), and strings to ForwardRef.""" if arg is None: return type(None) if isinstance(arg, str): - return ForwardRef(arg, module=module) + return ForwardRef(arg, module=module, is_class=allow_special_forms) return arg @@ -152,7 +152,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms= if is_argument: invalid_generic_forms += (Final,) - arg = _type_convert(arg, module=module) + arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms) if (isinstance(arg, _GenericAlias) and arg.__origin__ in invalid_generic_forms): raise TypeError(f"{arg} is not valid as type argument") diff --git a/Misc/NEWS.d/next/Library/2022-01-26-20-36-30.bpo-46539.23iW1d.rst b/Misc/NEWS.d/next/Library/2022-01-26-20-36-30.bpo-46539.23iW1d.rst new file mode 100644 index 00000000000000..2bdde21b6e58e5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-26-20-36-30.bpo-46539.23iW1d.rst @@ -0,0 +1 @@ +In :func:`typing.get_type_hints`, support evaluating stringified ``ClassVar`` and ``Final`` annotations inside ``Annotated``. Patch by Gregory Beauregard. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy