[pypy-commit] pypy py3.7: unparse annotations when __future__.annotations is imported

cfbolz pypy.commits at gmail.com
Mon Jan 6 04:55:32 EST 2020


Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: py3.7
Changeset: r98450:fa9634deaf0d
Date: 2020-01-06 10:54 +0100
http://bitbucket.org/pypy/pypy/changeset/fa9634deaf0d/

Log:	unparse annotations when __future__.annotations is imported

diff --git a/pypy/interpreter/astcompiler/consts.py b/pypy/interpreter/astcompiler/consts.py
--- a/pypy/interpreter/astcompiler/consts.py
+++ b/pypy/interpreter/astcompiler/consts.py
@@ -20,9 +20,11 @@
 CO_FUTURE_UNICODE_LITERALS = 0x20000
 CO_FUTURE_BARRY_AS_BDFL = 0x40000
 CO_FUTURE_GENERATOR_STOP = 0x80000
+CO_FUTURE_ANNOTATIONS     = 0x100000  # annotations become strings at runtime
+
 #pypy specific:
-CO_KILL_DOCSTRING = 0x100000
-CO_YIELD_INSIDE_TRY = 0x200000
+CO_KILL_DOCSTRING = 0x200000
+CO_YIELD_INSIDE_TRY = 0x400000
 
 PyCF_MASK = (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT |
              CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION |
diff --git a/pypy/interpreter/astcompiler/test/test_unparse.py b/pypy/interpreter/astcompiler/test/test_unparse.py
--- a/pypy/interpreter/astcompiler/test/test_unparse.py
+++ b/pypy/interpreter/astcompiler/test/test_unparse.py
@@ -80,6 +80,7 @@
 
     def test_if(self):
         self.check('a if b else c')
+        self.check('0 if not x else 1 if x > 0 else -1')
 
     def test_list(self):
         self.check('[]')
@@ -117,13 +118,14 @@
     def test_index(self):
         self.check('a[1]')
         self.check('a[1:5]')
-        self.check('a[1:5,7:12,:,5]')
+        self.check('a[1:5, 7:12, :, 5]')
         self.check('a[::1]')
         self.check('dict[(str, int)]', 'dict[str, int]')
 
     def test_attribute(self):
         self.check('a.b.c')
         self.check('1 .b')
+        self.check('1.5.b')
 
     def test_yield(self):
         self.check('(yield)')
@@ -149,6 +151,7 @@
         self.check('lambda *l: 1')
         self.check('lambda *, m, l=5: 1')
         self.check('lambda **foo: 1')
+        self.check('lambda a, **b: 45')
 
 
 class TestAstUnparseAnnotations(object):
@@ -174,3 +177,8 @@
         ast = self.get_ast("""a: list[int]""")
         res = unparse_annotations(self.space, ast)
         assert self.space.text_w(res.body[0].annotation.value) == 'list[int]'
+
+    def test_await(self):
+        ast = self.get_ast("""def f() -> await some.complicated[0].call(with_args=True or 1 is not 1): pass""")
+        res = unparse_annotations(self.space, ast)
+        assert self.space.text_w(res.returns.value) == "await some.complicated[0].call(with_args=True or 1 is not 1)"
diff --git a/pypy/interpreter/astcompiler/unparse.py b/pypy/interpreter/astcompiler/unparse.py
--- a/pypy/interpreter/astcompiler/unparse.py
+++ b/pypy/interpreter/astcompiler/unparse.py
@@ -228,7 +228,7 @@
             self.append_ascii(" if ")
             self.append_expr(node.test, PRIORITY_TEST + 1)
             self.append_ascii(" else ")
-            self.append_expr(node.orelse, PRIORITY_TEST + 1)
+            self.append_expr(node.orelse, PRIORITY_TEST)
 
     def visit_List(self, node):
         if node.elts is None:
@@ -342,7 +342,7 @@
     def visit_ExtSlice(self, node):
         for i, slice in enumerate(node.dims):
             if i > 0:
-                self.append_ascii(',')
+                self.append_ascii(', ')
             self.append_expr(slice)
 
     def visit_Attribute(self, node):
@@ -442,6 +442,7 @@
                             self.append_ascii('=')
                             self.append_expr(default)
                 if args.kwarg:
+                    first = self.append_if_not_first(first, ', ')
                     self.append_ascii('**')
                     self.append_expr(args.kwarg)
                 self.append_ascii(': ')
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -38,7 +38,7 @@
 # time you make pyc files incompatible.  This value ends up in the frozen
 # importlib, via MAGIC_NUMBER in module/_frozen_importlib/__init__.
 
-pypy_incremental_magic = 192 # bump it by 16
+pypy_incremental_magic = 208 # bump it by 16
 assert pypy_incremental_magic % 16 == 0
 assert pypy_incremental_magic < 3000 # the magic number of Python 3. There are
                                      # no known magic numbers below this value
diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py
--- a/pypy/interpreter/pycompiler.py
+++ b/pypy/interpreter/pycompiler.py
@@ -101,7 +101,7 @@
     """
     def __init__(self, space, override_version=None):
         PyCodeCompiler.__init__(self, space)
-        self.future_flags = future.futureFlags_3_5
+        self.future_flags = future.futureFlags_3_7
         self.parser = pyparse.PythonParser(space, self.future_flags)
         self.additional_rules = {}
         self.compiler_flags = self.future_flags.allowed_flags
@@ -129,7 +129,10 @@
         return self._compile_ast(node, info)
 
     def _compile_ast(self, node, info, source=None):
+        from pypy.interpreter.astcompiler.unparse import unparse_annotations
         space = self.space
+        if info.flags & consts.CO_FUTURE_ANNOTATIONS:
+            node = unparse_annotations(space, node)
         try:
             mod = optimize.optimize_ast(space, node, info)
             code = codegen.compile_ast(space, mod, info)
diff --git a/pypy/interpreter/pyparser/future.py b/pypy/interpreter/pyparser/future.py
--- a/pypy/interpreter/pyparser/future.py
+++ b/pypy/interpreter/pyparser/future.py
@@ -31,6 +31,7 @@
 futureFlags_2_7 = FutureFlags((2, 7, 0, 'final', 0))
 futureFlags_3_2 = FutureFlags((3, 2, 0, 'final', 0))
 futureFlags_3_5 = FutureFlags((3, 5, 0, 'final', 0))
+futureFlags_3_7 = FutureFlags((3, 7, 0, 'final', 0))
 
 
 class TokenIterator:
diff --git a/pypy/interpreter/test/apptest_annotations_string.py b/pypy/interpreter/test/apptest_annotations_string.py
new file mode 100644
--- /dev/null
+++ b/pypy/interpreter/test/apptest_annotations_string.py
@@ -0,0 +1,29 @@
+from __future__ import annotations
+
+import pytest
+
+a: int
+b: unknown
+
+def test_toplevel_annotation():
+    assert __annotations__['a'] == "int"
+    assert __annotations__['b'] == "unknown"
+
+
+def test_simple_with_target():
+    class C:
+        a: int = 1
+        assert __annotations__["a"] == "int"
+        assert a == 1
+
+def test_class_annotation():
+    class C:
+        a: list[int]
+        b: str
+        assert "__annotations__" in locals()
+    assert C.__annotations__ == {"a": "list[int]", "b": "str"}
+
+def test_func_annotations():
+    def f(a: list) -> a ** 39:
+        return 12
+    assert f.__annotations__ == {"a": "list", "return": "a ** 39"}


More information about the pypy-commit mailing list