https://github.com/python/cpython/commit/d308d33e098d8e176f1e5169225d3cf800ed6aa1
commit: d308d33e098d8e176f1e5169225d3cf800ed6aa1
branch: main
author: Mehdi Drissi <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2024-03-11T23:11:56-07:00
summary:
gh-89547: Support for nesting special forms like Final (#116096)
files:
A Misc/NEWS.d/next/Library/2024-02-28-17-50-42.gh-issue-89547.GetF38.rst
M Lib/test/test_typing.py
M Lib/typing.py
M Misc/ACKS
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 912384ab6bfe84..a9942b44f29ed9 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -4655,8 +4655,6 @@ def test_fail_with_bare_union(self):
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 F:
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 C:
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):
diff --git a/Lib/typing.py b/Lib/typing.py
index cca9525d632ea5..b2350433953ccd 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -653,7 +653,7 @@ class Starship:
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 @@ class FastConnector(Connection):
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
diff --git a/Misc/ACKS b/Misc/ACKS
index f01c7a70a65dc5..03e458d170d2b8 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -470,6 +470,7 @@ Allen Downey
Cesar Douady
Dean Draayer
Fred L. Drake, Jr.
+Mehdi Drissi
Derk Drukker
John DuBois
Paul Dubois
diff --git
a/Misc/NEWS.d/next/Library/2024-02-28-17-50-42.gh-issue-89547.GetF38.rst
b/Misc/NEWS.d/next/Library/2024-02-28-17-50-42.gh-issue-89547.GetF38.rst
new file mode 100644
index 00000000000000..7be4591b83a8f3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-02-28-17-50-42.gh-issue-89547.GetF38.rst
@@ -0,0 +1 @@
+Add support for nested typing special forms like Final[ClassVar[int]].
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]