[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