summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2024-05-22 02:38:12 (GMT)
committerGitHub <noreply@github.com>2024-05-22 02:38:12 (GMT)
commite9875ecb5dd3a9c44a184c71cc562ce1fea6e03b (patch)
tree9b8aca9a11a3c8e1e1278cbe0293a0eab5f622a2 /Lib
parent73ab83b27f105a4509046ce26e35f20d66625195 (diff)
downloadcpython-e9875ecb5dd3a9c44a184c71cc562ce1fea6e03b.zip
cpython-e9875ecb5dd3a9c44a184c71cc562ce1fea6e03b.tar.gz
cpython-e9875ecb5dd3a9c44a184c71cc562ce1fea6e03b.tar.bz2
gh-119180: PEP 649: Add __annotate__ attributes (#119209)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_sys.py2
-rw-r--r--Lib/test/test_type_annotations.py44
-rw-r--r--Lib/test/test_typing.py2
-rw-r--r--Lib/typing.py1
4 files changed, 47 insertions, 2 deletions
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index ee3bd00..8fe1d77 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1564,7 +1564,7 @@ class SizeofTest(unittest.TestCase):
check(x, size('3Pi2cP7P2ic??2P'))
# function
def func(): pass
- check(func, size('15Pi'))
+ check(func, size('16Pi'))
class c():
@staticmethod
def foo():
diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py
index 3dbb35a..5e3c334 100644
--- a/Lib/test/test_type_annotations.py
+++ b/Lib/test/test_type_annotations.py
@@ -1,4 +1,5 @@
import textwrap
+import types
import unittest
from test.support import run_code
@@ -212,3 +213,46 @@ class TestSetupAnnotations(unittest.TestCase):
case 0:
x: int = 1
""")
+
+
+class AnnotateTests(unittest.TestCase):
+ """See PEP 649."""
+ def test_manual_annotate(self):
+ def f():
+ pass
+ mod = types.ModuleType("mod")
+ class X:
+ pass
+
+ for obj in (f, mod, X):
+ with self.subTest(obj=obj):
+ self.check_annotations(obj)
+
+ def check_annotations(self, f):
+ self.assertEqual(f.__annotations__, {})
+ self.assertIs(f.__annotate__, None)
+
+ with self.assertRaisesRegex(TypeError, "__annotate__ must be callable or None"):
+ f.__annotate__ = 42
+ f.__annotate__ = lambda: 42
+ with self.assertRaisesRegex(TypeError, r"takes 0 positional arguments but 1 was given"):
+ print(f.__annotations__)
+
+ f.__annotate__ = lambda x: 42
+ with self.assertRaisesRegex(TypeError, r"__annotate__ returned non-dict of type 'int'"):
+ print(f.__annotations__)
+
+ f.__annotate__ = lambda x: {"x": x}
+ self.assertEqual(f.__annotations__, {"x": 1})
+
+ # Setting annotate to None does not invalidate the cached __annotations__
+ f.__annotate__ = None
+ self.assertEqual(f.__annotations__, {"x": 1})
+
+ # But setting it to a new callable does
+ f.__annotate__ = lambda x: {"y": x}
+ self.assertEqual(f.__annotations__, {"y": 1})
+
+ # Setting f.__annotations__ also clears __annotate__
+ f.__annotations__ = {"z": 43}
+ self.assertIs(f.__annotate__, None)
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 64c4c49..dac55ce 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -3723,7 +3723,7 @@ class ProtocolTests(BaseTestCase):
acceptable_extra_attrs = {
'_is_protocol', '_is_runtime_protocol', '__parameters__',
- '__init__', '__annotations__', '__subclasshook__',
+ '__init__', '__annotations__', '__subclasshook__', '__annotate__',
}
self.assertLessEqual(vars(NonP).keys(), vars(C).keys() | acceptable_extra_attrs)
self.assertLessEqual(
diff --git a/Lib/typing.py b/Lib/typing.py
index 4345745..be49aa6 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1889,6 +1889,7 @@ _SPECIAL_NAMES = frozenset({
'__init__', '__module__', '__new__', '__slots__',
'__subclasshook__', '__weakref__', '__class_getitem__',
'__match_args__', '__static_attributes__', '__firstlineno__',
+ '__annotate__',
})
# These special attributes will be not collected as protocol members.