Skip to content

Commit d308d33

Browse files
gh-89547: Support for nesting special forms like Final (#116096)
1 parent 4fa95c6 commit d308d33

File tree

4 files changed

+32
-14
lines changed

4 files changed

+32
-14
lines changed

Lib/test/test_typing.py

+28-12
Original file line numberDiff line numberDiff line change
@@ -4655,8 +4655,6 @@ def test_fail_with_bare_union(self):
46554655
List[Union]
46564656
with self.assertRaises(TypeError):
46574657
Tuple[Optional]
4658-
with self.assertRaises(TypeError):
4659-
ClassVar[ClassVar[int]]
46604658
with self.assertRaises(TypeError):
46614659
List[ClassVar[int]]
46624660

@@ -6014,16 +6012,6 @@ class F:
60146012
for clazz in [C, D, E, F]:
60156013
self.assertEqual(get_type_hints(clazz), expected_result)
60166014

6017-
def test_nested_classvar_fails_forward_ref_check(self):
6018-
class E:
6019-
foo: 'typing.ClassVar[typing.ClassVar[int]]' = 7
6020-
class F:
6021-
foo: ClassVar['ClassVar[int]'] = 7
6022-
6023-
for clazz in [E, F]:
6024-
with self.assertRaises(TypeError):
6025-
get_type_hints(clazz)
6026-
60276015
def test_meta_no_type_check(self):
60286016
depr_msg = (
60296017
"'typing.no_type_check_decorator' is deprecated "
@@ -8716,6 +8704,34 @@ class C:
87168704
self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int])
87178705
self.assertEqual(get_type_hints(C, globals())['const'], Final[int])
87188706

8707+
def test_special_forms_nesting(self):
8708+
# These are uncommon types and are to ensure runtime
8709+
# is lax on validation. See gh-89547 for more context.
8710+
class CF:
8711+
x: ClassVar[Final[int]]
8712+
8713+
class FC:
8714+
x: Final[ClassVar[int]]
8715+
8716+
class ACF:
8717+
x: Annotated[ClassVar[Final[int]], "a decoration"]
8718+
8719+
class CAF:
8720+
x: ClassVar[Annotated[Final[int], "a decoration"]]
8721+
8722+
class AFC:
8723+
x: Annotated[Final[ClassVar[int]], "a decoration"]
8724+
8725+
class FAC:
8726+
x: Final[Annotated[ClassVar[int], "a decoration"]]
8727+
8728+
self.assertEqual(get_type_hints(CF, globals())['x'], ClassVar[Final[int]])
8729+
self.assertEqual(get_type_hints(FC, globals())['x'], Final[ClassVar[int]])
8730+
self.assertEqual(get_type_hints(ACF, globals())['x'], ClassVar[Final[int]])
8731+
self.assertEqual(get_type_hints(CAF, globals())['x'], ClassVar[Final[int]])
8732+
self.assertEqual(get_type_hints(AFC, globals())['x'], Final[ClassVar[int]])
8733+
self.assertEqual(get_type_hints(FAC, globals())['x'], Final[ClassVar[int]])
8734+
87198735
def test_cannot_subclass(self):
87208736
with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"):
87218737
class C(Annotated):

Lib/typing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ class Starship:
653653
Note that ClassVar is not a class itself, and should not
654654
be used with isinstance() or issubclass().
655655
"""
656-
item = _type_check(parameters, f'{self} accepts only single type.')
656+
item = _type_check(parameters, f'{self} accepts only single type.', allow_special_forms=True)
657657
return _GenericAlias(self, (item,))
658658

659659
@_SpecialForm
@@ -675,7 +675,7 @@ class FastConnector(Connection):
675675
676676
There is no runtime checking of these properties.
677677
"""
678-
item = _type_check(parameters, f'{self} accepts only single type.')
678+
item = _type_check(parameters, f'{self} accepts only single type.', allow_special_forms=True)
679679
return _GenericAlias(self, (item,))
680680

681681
@_SpecialForm

Misc/ACKS

+1
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ Allen Downey
470470
Cesar Douady
471471
Dean Draayer
472472
Fred L. Drake, Jr.
473+
Mehdi Drissi
473474
Derk Drukker
474475
John DuBois
475476
Paul Dubois
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add support for nested typing special forms like Final[ClassVar[int]].

0 commit comments

Comments
 (0)