bpo-42725: Render annotations effectless on symbol table with PEP 563 (GH-25583)
diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py
index 8a09853..4ef1123 100644
--- a/Lib/test/test_future.py
+++ b/Lib/test/test_future.py
@@ -171,6 +171,14 @@ def assertAnnotationEqual(
self.assertEqual(actual, expected)
+ def _exec_future(self, code):
+ scope = {}
+ exec(
+ "from __future__ import annotations\n"
+ + code, {}, scope
+ )
+ return scope
+
def test_annotations(self):
eq = self.assertAnnotationEqual
eq('...')
@@ -310,10 +318,6 @@ def test_annotations(self):
eq("f'{x}'")
eq("f'{x!r}'")
eq("f'{x!a}'")
- eq('(yield from outside_of_generator)')
- eq('(yield)')
- eq('(yield a + b)')
- eq('await some.complicated[0].call(with_args=True or 1 is not 1)')
eq('[x for x in (a if b else c)]')
eq('[x for x in a if (b if c else d)]')
eq('f(x for x in a)')
@@ -321,8 +325,6 @@ def test_annotations(self):
eq('f((x for x in a), 2)')
eq('(((a)))', 'a')
eq('(((a, b)))', '(a, b)')
- eq("(x := 10)")
- eq("f'{(x := 10):=10}'")
eq("1 + 2 + 3")
def test_fstring_debug_annotations(self):
@@ -354,6 +356,53 @@ def test_annotation_with_complex_target(self):
"object.__debug__: int"
)
+ def test_annotations_symbol_table_pass(self):
+ namespace = self._exec_future(dedent("""
+ from __future__ import annotations
+
+ def foo():
+ outer = 1
+ def bar():
+ inner: outer = 1
+ return bar
+ """))
+
+ foo = namespace.pop("foo")
+ self.assertIsNone(foo().__closure__)
+ self.assertEqual(foo.__code__.co_cellvars, ())
+ self.assertEqual(foo().__code__.co_freevars, ())
+
+ def test_annotations_forbidden(self):
+ with self.assertRaises(SyntaxError):
+ self._exec_future("test: (yield)")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future("test.test: (yield a + b)")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future("test[something]: (yield from x)")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future("def func(test: (yield from outside_of_generator)): pass")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future("def test() -> (await y): pass")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future("async def test() -> something((a := b)): pass")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future("test: await some.complicated[0].call(with_args=True or 1 is not 1)")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future("test: f'{(x := 10):=10}'")
+
+ with self.assertRaises(SyntaxError):
+ self._exec_future(dedent("""\
+ def foo():
+ def bar(arg: (yield)): pass
+ """))
+
if __name__ == "__main__":
unittest.main()