gh-89547: Support for nesting special forms like Final (#116096)

This commit is contained in:
Mehdi Drissi 2024-03-11 23:11:56 -07:00 committed by GitHub
parent 4fa95c6ec3
commit d308d33e09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 32 additions and 14 deletions

View File

@ -4655,8 +4655,6 @@ class GenericTests(BaseTestCase):
List[Union]
with self.assertRaises(TypeError):
Tuple[Optional]
with self.assertRaises(TypeError):
ClassVar[ClassVar[int]]
with self.assertRaises(TypeError):
List[ClassVar[int]]
@ -6014,16 +6012,6 @@ class ForwardRefTests(BaseTestCase):
for clazz in [C, D, E, F]:
self.assertEqual(get_type_hints(clazz), expected_result)
def test_nested_classvar_fails_forward_ref_check(self):
class E:
foo: 'typing.ClassVar[typing.ClassVar[int]]' = 7
class F:
foo: ClassVar['ClassVar[int]'] = 7
for clazz in [E, F]:
with self.assertRaises(TypeError):
get_type_hints(clazz)
def test_meta_no_type_check(self):
depr_msg = (
"'typing.no_type_check_decorator' is deprecated "
@ -8716,6 +8704,34 @@ class AnnotatedTests(BaseTestCase):
self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int])
self.assertEqual(get_type_hints(C, globals())['const'], Final[int])
def test_special_forms_nesting(self):
# These are uncommon types and are to ensure runtime
# is lax on validation. See gh-89547 for more context.
class CF:
x: ClassVar[Final[int]]
class FC:
x: Final[ClassVar[int]]
class ACF:
x: Annotated[ClassVar[Final[int]], "a decoration"]
class CAF:
x: ClassVar[Annotated[Final[int], "a decoration"]]
class AFC:
x: Annotated[Final[ClassVar[int]], "a decoration"]
class FAC:
x: Final[Annotated[ClassVar[int], "a decoration"]]
self.assertEqual(get_type_hints(CF, globals())['x'], ClassVar[Final[int]])
self.assertEqual(get_type_hints(FC, globals())['x'], Final[ClassVar[int]])
self.assertEqual(get_type_hints(ACF, globals())['x'], ClassVar[Final[int]])
self.assertEqual(get_type_hints(CAF, globals())['x'], ClassVar[Final[int]])
self.assertEqual(get_type_hints(AFC, globals())['x'], Final[ClassVar[int]])
self.assertEqual(get_type_hints(FAC, globals())['x'], Final[ClassVar[int]])
def test_cannot_subclass(self):
with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"):
class C(Annotated):

View File

@ -653,7 +653,7 @@ def ClassVar(self, parameters):
Note that ClassVar is not a class itself, and should not
be used with isinstance() or issubclass().
"""
item = _type_check(parameters, f'{self} accepts only single type.')
item = _type_check(parameters, f'{self} accepts only single type.', allow_special_forms=True)
return _GenericAlias(self, (item,))
@_SpecialForm
@ -675,7 +675,7 @@ def Final(self, parameters):
There is no runtime checking of these properties.
"""
item = _type_check(parameters, f'{self} accepts only single type.')
item = _type_check(parameters, f'{self} accepts only single type.', allow_special_forms=True)
return _GenericAlias(self, (item,))
@_SpecialForm

View File

@ -470,6 +470,7 @@ Allen Downey
Cesar Douady
Dean Draayer
Fred L. Drake, Jr.
Mehdi Drissi
Derk Drukker
John DuBois
Paul Dubois

View File

@ -0,0 +1 @@
Add support for nested typing special forms like Final[ClassVar[int]].