Hello community, here is the log from the commit of package python-astunparse for openSUSE:Factory checked in at 2019-03-06 15:52:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-astunparse (Old) and /work/SRC/openSUSE:Factory/.python-astunparse.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-astunparse" Wed Mar 6 15:52:38 2019 rev:3 rq:682137 version:1.6.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-astunparse/python-astunparse.changes 2018-12-12 17:25:21.291115457 +0100 +++ /work/SRC/openSUSE:Factory/.python-astunparse.new.28833/python-astunparse.changes 2019-03-06 15:52:46.244419332 +0100 @@ -1,0 +2,10 @@ +Wed Mar 6 12:29:21 UTC 2019 - Tomáš Chvátal <tchva...@suse.com> + +- Update to 1.6.2: + * Python 3.7 compatibility + * Fix the roundtripping of very complex f-strings. + * Add support for the Constant node in Python 3.8 + * Add tests to the sdist +- Execute tests + +------------------------------------------------------------------- Old: ---- astunparse-1.5.0.tar.gz New: ---- astunparse-1.6.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-astunparse.spec ++++++ --- /var/tmp/diff_new_pack.DwFvhU/_old 2019-03-06 15:52:47.656419048 +0100 +++ /var/tmp/diff_new_pack.DwFvhU/_new 2019-03-06 15:52:47.656419048 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-astunparse # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,19 +18,21 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-astunparse -Version: 1.5.0 +Version: 1.6.2 Release: 0 Summary: An AST unparser for Python License: BSD-3-Clause AND Python-2.0 Group: Development/Languages/Python -Url: https://github.com/simonpercivall/astunparse +URL: https://github.com/simonpercivall/astunparse Source: https://files.pythonhosted.org/packages/source/a/astunparse/astunparse-%{version}.tar.gz BuildRequires: %{python_module setuptools} +BuildRequires: %{python_module six >= 1.6.1} +BuildRequires: %{python_module wheel >= 0.23.0} BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-six >= 1.6.1 +Requires: python-wheel >= 0.23.0 BuildArch: noarch - %python_subpackages %description @@ -56,8 +58,11 @@ %python_install %python_expand %fdupes %{buildroot}%{$python_sitelib} +%check +%python_exec setup.py test + %files %{python_files} -%doc AUTHORS.rst README.rst +%doc AUTHORS.rst README.rst HISTORY.rst %license LICENSE %{python_sitelib}/* ++++++ astunparse-1.5.0.tar.gz -> astunparse-1.6.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/AUTHORS.rst new/astunparse-1.6.2/AUTHORS.rst --- old/astunparse-1.5.0/AUTHORS.rst 2014-04-03 08:47:47.000000000 +0200 +++ new/astunparse-1.6.2/AUTHORS.rst 2018-09-30 23:42:18.000000000 +0200 @@ -12,3 +12,8 @@ * The Python Software Foundation * Bogdan Opanchuk +* Vladimir Iakovlev +* Thomas Grainger +* Amund Hov +* Jakub Wilk +* Mateusz Bysiek diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/CONTRIBUTING.rst new/astunparse-1.6.2/CONTRIBUTING.rst --- old/astunparse-1.5.0/CONTRIBUTING.rst 2014-03-28 23:43:02.000000000 +0100 +++ new/astunparse-1.6.2/CONTRIBUTING.rst 2018-09-30 22:14:38.000000000 +0200 @@ -42,7 +42,7 @@ Submit Feedback ~~~~~~~~~~~~~~~ -The best way to send feedback is to file an issueat https://github.com/simonpercivall/astunparse/issues. +The best way to send feedback is to file an issue at https://github.com/simonpercivall/astunparse/issues. If you are proposing a feature: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/HISTORY.rst new/astunparse-1.6.2/HISTORY.rst --- old/astunparse-1.5.0/HISTORY.rst 2017-02-05 03:32:33.000000000 +0100 +++ new/astunparse-1.6.2/HISTORY.rst 2019-01-19 16:08:34.000000000 +0100 @@ -3,6 +3,22 @@ Here's the recent changes to AST Unparser. +1.6.2 - 2019-01-19 +~~~~~~~~~~~~~~~~~~ + +* Add support for the Constant node in Python 3.8 +* Add tests to the sdist + +1.6.1 - 2018-10-03 +~~~~~~~~~~~~~~~~~~ + +* Fix the roundtripping of very complex f-strings. + +1.6.0 - 2018-09-30 +~~~~~~~~~~~~~~~~~~ + +* Python 3.7 compatibility + 1.5.0 - 2017-02-05 ~~~~~~~~~~~~~~~~~~ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/MANIFEST.in new/astunparse-1.6.2/MANIFEST.in --- old/astunparse-1.5.0/MANIFEST.in 2014-03-28 23:43:02.000000000 +0100 +++ new/astunparse-1.6.2/MANIFEST.in 2019-01-19 16:06:10.000000000 +0100 @@ -4,4 +4,5 @@ include LICENSE include README.rst include requirements.txt -include test_requirements.txt \ No newline at end of file +include test_requirements.txt +recursive-include tests *.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/PKG-INFO new/astunparse-1.6.2/PKG-INFO --- old/astunparse-1.5.0/PKG-INFO 2017-02-05 03:37:40.000000000 +0100 +++ new/astunparse-1.6.2/PKG-INFO 2019-01-19 19:00:44.000000000 +0100 @@ -1,10 +1,10 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: astunparse -Version: 1.5.0 +Version: 1.6.2 Summary: An AST unparser for Python Home-page: https://github.com/simonpercivall/astunparse -Author: Simon Percivall -Author-email: perciv...@gmail.com +Maintainer: Simon Percivall +Maintainer-email: perciv...@gmail.com License: BSD Description: ============ AST Unparser @@ -89,6 +89,22 @@ Here's the recent changes to AST Unparser. + 1.6.2 - 2019-01-19 + ~~~~~~~~~~~~~~~~~~ + + * Add support for the Constant node in Python 3.8 + * Add tests to the sdist + + 1.6.1 - 2018-10-03 + ~~~~~~~~~~~~~~~~~~ + + * Fix the roundtripping of very complex f-strings. + + 1.6.0 - 2018-09-30 + ~~~~~~~~~~~~~~~~~~ + + * Python 3.7 compatibility + 1.5.0 - 2017-02-05 ~~~~~~~~~~~~~~~~~~ @@ -137,4 +153,5 @@ Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Software Development :: Code Generators diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/lib/astunparse/__init__.py new/astunparse-1.6.2/lib/astunparse/__init__.py --- old/astunparse-1.5.0/lib/astunparse/__init__.py 2017-02-05 03:30:20.000000000 +0100 +++ new/astunparse-1.6.2/lib/astunparse/__init__.py 2019-01-19 16:07:47.000000000 +0100 @@ -5,7 +5,7 @@ from .printer import Printer -__version__ = '1.5.0' +__version__ = '1.6.2' def unparse(tree): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/lib/astunparse/unparser.py new/astunparse-1.6.2/lib/astunparse/unparser.py --- old/astunparse-1.5.0/lib/astunparse/unparser.py 2017-02-05 03:30:16.000000000 +0100 +++ new/astunparse-1.6.2/lib/astunparse/unparser.py 2019-01-19 16:06:10.000000000 +0100 @@ -328,12 +328,12 @@ self.dispatch(t.body) self.leave() - def _generic_FunctionDef(self, t, async=False): + def _generic_FunctionDef(self, t, async_=False): self.write("\n") for deco in t.decorator_list: self.fill("@") self.dispatch(deco) - self.fill(("async " if async else "") + "def " + t.name + "(") + self.fill(("async " if async_ else "") + "def " + t.name + "(") self.dispatch(t.args) self.write(")") if getattr(t, "returns", False): @@ -347,10 +347,10 @@ self._generic_FunctionDef(t) def _AsyncFunctionDef(self, t): - self._generic_FunctionDef(t, async=True) + self._generic_FunctionDef(t, async_=True) - def _generic_For(self, t, async=False): - self.fill("async for " if async else "for ") + def _generic_For(self, t, async_=False): + self.fill("async for " if async_ else "for ") self.dispatch(t.target) self.write(" in ") self.dispatch(t.iter) @@ -367,7 +367,7 @@ self._generic_For(t) def _AsyncFor(self, t): - self._generic_For(t, async=True) + self._generic_For(t, async_=True) def _If(self, t): self.fill("if ") @@ -403,8 +403,8 @@ self.dispatch(t.orelse) self.leave() - def _generic_With(self, t, async=False): - self.fill("async with " if async else "with ") + def _generic_With(self, t, async_=False): + self.fill("async with " if async_ else "with ") if hasattr(t, 'items'): interleave(lambda: self.write(", "), self.dispatch, t.items) else: @@ -420,7 +420,7 @@ self._generic_With(t) def _AsyncWith(self, t): - self._generic_With(t, async=True) + self._generic_With(t, async_=True) # expr def _Bytes(self, t): @@ -442,33 +442,64 @@ else: assert False, "shouldn't get here" - format_conversions = {97: 'a', 114: 'r', 115: 's'} + def _JoinedStr(self, t): + # JoinedStr(expr* values) + self.write("f") + string = StringIO() + self._fstring_JoinedStr(t, string.write) + # Deviation from `unparse.py`: Try to find an unused quote. + # This change is made to handle _very_ complex f-strings. + v = string.getvalue() + if '\n' in v or '\r' in v: + quote_types = ["'''", '"""'] + else: + quote_types = ["'", '"', '"""', "'''"] + for quote_type in quote_types: + if quote_type not in v: + v = "{quote_type}{v}{quote_type}".format(quote_type=quote_type, v=v) + break + else: + v = repr(v) + self.write(v) def _FormattedValue(self, t): # FormattedValue(expr value, int? conversion, expr? format_spec) - self.write("{") - self.dispatch(t.value) - if t.conversion is not None and t.conversion != -1: - self.write("!") - self.write(self.format_conversions[t.conversion]) - #raise NotImplementedError(ast.dump(t, True, True)) - if t.format_spec is not None: - self.write(":") - if isinstance(t.format_spec, ast.Str): - self.write(t.format_spec.s) - else: - self.dispatch(t.format_spec) - self.write("}") + self.write("f") + string = StringIO() + self._fstring_JoinedStr(t, string.write) + self.write(repr(string.getvalue())) - def _JoinedStr(self, t): - # JoinedStr(expr* values) - self.write("f'''") + def _fstring_JoinedStr(self, t, write): for value in t.values: - if isinstance(value, ast.Str): - self.write(value.s) - else: - self.dispatch(value) - self.write("'''") + meth = getattr(self, "_fstring_" + type(value).__name__) + meth(value, write) + + def _fstring_Str(self, t, write): + value = t.s.replace("{", "{{").replace("}", "}}") + write(value) + + def _fstring_Constant(self, t, write): + assert isinstance(t.value, str) + value = t.value.replace("{", "{{").replace("}", "}}") + write(value) + + def _fstring_FormattedValue(self, t, write): + write("{") + expr = StringIO() + Unparser(t.value, expr) + expr = expr.getvalue().rstrip("\n") + if expr.startswith("{"): + write(" ") # Separate pair of opening brackets as "{ {" + write(expr) + if t.conversion != -1: + conversion = chr(t.conversion) + assert conversion in "sra" + write("!{conversion}".format(conversion=conversion)) + if t.format_spec: + write(":") + meth = getattr(self, "_fstring_" + type(t.format_spec).__name__) + meth(t.format_spec, write) + write("}") def _Name(self, t): self.write(t.id) @@ -481,6 +512,28 @@ self.dispatch(t.value) self.write("`") + def _write_constant(self, value): + if isinstance(value, (float, complex)): + # Substitute overflowing decimal literal for AST infinities. + self.write(repr(value).replace("inf", INFSTR)) + else: + self.write(repr(value)) + + def _Constant(self, t): + value = t.value + if isinstance(value, tuple): + self.write("(") + if len(value) == 1: + self._write_constant(value[0]) + self.write(",") + else: + interleave(lambda: self.write(", "), self._write_constant, value) + self.write(")") + elif value is Ellipsis: # instead of `...` for Py2 compatibility + self.write("...") + else: + self._write_constant(t.value) + def _Num(self, t): repr_n = repr(t.n) if six.PY3: @@ -561,11 +614,19 @@ self.write("{") def write_pair(pair): (k, v) = pair - self.dispatch(k) - self.write(": ") - self.dispatch(v) - interleave(lambda: self.write(", "), write_pair, zip(t.keys, t.values)) - self.write("}") + if k is None: + self.write('**') + self.dispatch(v) + else: + self.dispatch(k) + self.write(": ") + self.dispatch(v) + self.write(",") + self._indent +=1 + self.fill("") + interleave(lambda: self.fill(""), write_pair, zip(t.keys, t.values)) + self._indent -=1 + self.fill("}") def _Tuple(self, t): self.write("(") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/lib/astunparse.egg-info/PKG-INFO new/astunparse-1.6.2/lib/astunparse.egg-info/PKG-INFO --- old/astunparse-1.5.0/lib/astunparse.egg-info/PKG-INFO 2017-02-05 03:37:40.000000000 +0100 +++ new/astunparse-1.6.2/lib/astunparse.egg-info/PKG-INFO 2019-01-19 19:00:44.000000000 +0100 @@ -1,10 +1,10 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: astunparse -Version: 1.5.0 +Version: 1.6.2 Summary: An AST unparser for Python Home-page: https://github.com/simonpercivall/astunparse -Author: Simon Percivall -Author-email: perciv...@gmail.com +Maintainer: Simon Percivall +Maintainer-email: perciv...@gmail.com License: BSD Description: ============ AST Unparser @@ -89,6 +89,22 @@ Here's the recent changes to AST Unparser. + 1.6.2 - 2019-01-19 + ~~~~~~~~~~~~~~~~~~ + + * Add support for the Constant node in Python 3.8 + * Add tests to the sdist + + 1.6.1 - 2018-10-03 + ~~~~~~~~~~~~~~~~~~ + + * Fix the roundtripping of very complex f-strings. + + 1.6.0 - 2018-09-30 + ~~~~~~~~~~~~~~~~~~ + + * Python 3.7 compatibility + 1.5.0 - 2017-02-05 ~~~~~~~~~~~~~~~~~~ @@ -137,4 +153,5 @@ Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Software Development :: Code Generators diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/lib/astunparse.egg-info/SOURCES.txt new/astunparse-1.6.2/lib/astunparse.egg-info/SOURCES.txt --- old/astunparse-1.5.0/lib/astunparse.egg-info/SOURCES.txt 2017-02-05 03:37:40.000000000 +0100 +++ new/astunparse-1.6.2/lib/astunparse.egg-info/SOURCES.txt 2019-01-19 19:00:44.000000000 +0100 @@ -17,4 +17,8 @@ lib/astunparse.egg-info/dependency_links.txt lib/astunparse.egg-info/not-zip-safe lib/astunparse.egg-info/requires.txt -lib/astunparse.egg-info/top_level.txt \ No newline at end of file +lib/astunparse.egg-info/top_level.txt +tests/__init__.py +tests/common.py +tests/test_dump.py +tests/test_unparse.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/lib/astunparse.egg-info/requires.txt new/astunparse-1.6.2/lib/astunparse.egg-info/requires.txt --- old/astunparse-1.5.0/lib/astunparse.egg-info/requires.txt 2017-02-05 03:37:40.000000000 +0100 +++ new/astunparse-1.6.2/lib/astunparse.egg-info/requires.txt 2019-01-19 19:00:44.000000000 +0100 @@ -1,2 +1,2 @@ -wheel >= 0.23.0, < 1.0 -six >= 1.6.1, < 2.0 +wheel<1.0,>=0.23.0 +six<2.0,>=1.6.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/setup.cfg new/astunparse-1.6.2/setup.cfg --- old/astunparse-1.5.0/setup.cfg 2017-02-05 03:37:40.000000000 +0100 +++ new/astunparse-1.6.2/setup.cfg 2019-01-19 19:00:44.000000000 +0100 @@ -4,5 +4,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/setup.py new/astunparse-1.6.2/setup.py --- old/astunparse-1.5.0/setup.py 2017-02-05 03:30:16.000000000 +0100 +++ new/astunparse-1.6.2/setup.py 2018-09-30 23:42:18.000000000 +0200 @@ -52,6 +52,7 @@ 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Software Development :: Code Generators', ], test_suite='tests', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/tests/__init__.py new/astunparse-1.6.2/tests/__init__.py --- old/astunparse-1.5.0/tests/__init__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/astunparse-1.6.2/tests/__init__.py 2014-03-28 23:43:02.000000000 +0100 @@ -0,0 +1,2 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/tests/common.py new/astunparse-1.6.2/tests/common.py --- old/astunparse-1.5.0/tests/common.py 1970-01-01 01:00:00.000000000 +0100 +++ new/astunparse-1.6.2/tests/common.py 2018-10-03 11:01:13.000000000 +0200 @@ -0,0 +1,425 @@ +import codecs +import os +import sys +if sys.version_info < (2, 7): + import unittest2 as unittest +else: + import unittest + +import six +if six.PY3: + import tokenize +else: + from lib2to3.pgen2 import tokenize + +def read_pyfile(filename): + """Read and return the contents of a Python source file (as a + string), taking into account the file encoding.""" + if six.PY3: + with open(filename, "rb") as pyfile: + encoding = tokenize.detect_encoding(pyfile.readline)[0] + with codecs.open(filename, "r", encoding=encoding) as pyfile: + source = pyfile.read() + else: + with open(filename, "r") as pyfile: + source = pyfile.read() + return source + +code_parseable_in_all_parser_modes = """\ +(a + b + c) * (d + e + f) +""" + +for_else = """\ +def f(): + for x in range(10): + break + else: + y = 2 + z = 3 +""" + +while_else = """\ +def g(): + while True: + break + else: + y = 2 + z = 3 +""" + +relative_import = """\ +from . import fred +from .. import barney +from .australia import shrimp as prawns +""" + +import_many = """\ +import fred, barney +""" + +nonlocal_ex = """\ +def f(): + x = 1 + def g(): + nonlocal x + x = 2 + y = 7 + def h(): + nonlocal x, y +""" + +# also acts as test for 'except ... as ...' +raise_from = """\ +try: + 1 / 0 +except ZeroDivisionError as e: + raise ArithmeticError from e +""" + +async_comprehensions_and_generators = """\ +async def async_function(): + my_set = {i async for i in aiter() if i % 2} + my_list = [i async for i in aiter() if i % 2] + my_dict = {i: -i async for i in aiter() if i % 2} + my_gen = (i ** 2 async for i in agen()) + my_other_gen = (i - 1 async for i in agen() if i % 2) +""" + +class_decorator = """\ +@f1(arg) +@f2 +class Foo: pass +""" + +elif1 = """\ +if cond1: + suite1 +elif cond2: + suite2 +else: + suite3 +""" + +elif2 = """\ +if cond1: + suite1 +elif cond2: + suite2 +""" + +try_except_finally = """\ +try: + suite1 +except ex1: + suite2 +except ex2: + suite3 +else: + suite4 +finally: + suite5 +""" + +with_simple = """\ +with f(): + suite1 +""" + +with_as = """\ +with f() as x: + suite1 +""" + +with_two_items = """\ +with f() as x, g() as y: + suite1 +""" + +a_repr = """\ +`{}` +""" + +complex_f_string = '''\ +f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\' +''' + +async_function_def = """\ +async def f(): + suite1 +""" + +async_for = """\ +async def f(): + async for _ in reader: + suite1 +""" + +async_with = """\ +async def f(): + async with g(): + suite1 +""" + +async_with_as = """\ +async def f(): + async with g() as x: + suite1 +""" + +class AstunparseCommonTestCase: + # Tests for specific bugs found in earlier versions of unparse + + def assertASTEqual(self, dump1, dump2): + raise NotImplementedError() + + def check_roundtrip(self, code1, filename="internal", mode="exec"): + raise NotImplementedError() + + test_directories = [ + os.path.join(getattr(sys, 'real_prefix', sys.prefix), + 'lib', 'python%s.%s' % sys.version_info[:2])] + + def test_files(self): + names = [] + for test_dir in self.test_directories: + for n in os.listdir(test_dir): + if n.endswith('.py') and not n.startswith('bad'): + names.append(os.path.join(test_dir, n)) + + for filename in names: + print('Testing %s' % filename) + source = read_pyfile(filename) + self.check_roundtrip(source) + + def test_parser_modes(self): + for mode in ['exec', 'single', 'eval']: + self.check_roundtrip(code_parseable_in_all_parser_modes, mode=mode) + + def test_del_statement(self): + self.check_roundtrip("del x, y, z") + + def test_shifts(self): + self.check_roundtrip("45 << 2") + self.check_roundtrip("13 >> 7") + + def test_for_else(self): + self.check_roundtrip(for_else) + + def test_while_else(self): + self.check_roundtrip(while_else) + + def test_unary_parens(self): + self.check_roundtrip("(-1)**7") + self.check_roundtrip("(-1.)**8") + self.check_roundtrip("(-1j)**6") + self.check_roundtrip("not True or False") + self.check_roundtrip("True or not False") + + def test_integer_parens(self): + self.check_roundtrip("3 .__abs__()") + + def test_huge_float(self): + self.check_roundtrip("1e1000") + self.check_roundtrip("-1e1000") + self.check_roundtrip("1e1000j") + self.check_roundtrip("-1e1000j") + + @unittest.skipUnless(six.PY2, "Only works for Python 2") + def test_min_int27(self): + self.check_roundtrip(str(-sys.maxint-1)) + self.check_roundtrip("-(%s)" % (sys.maxint + 1)) + + @unittest.skipUnless(six.PY3, "Only works for Python 3") + def test_min_int30(self): + self.check_roundtrip(str(-2**31)) + self.check_roundtrip(str(-2**63)) + + def test_imaginary_literals(self): + self.check_roundtrip("7j") + self.check_roundtrip("-7j") + self.check_roundtrip("0j") + self.check_roundtrip("-0j") + if six.PY2: + self.check_roundtrip("-(7j)") + self.check_roundtrip("-(0j)") + + def test_negative_zero(self): + self.check_roundtrip("-0") + self.check_roundtrip("-(0)") + self.check_roundtrip("-0b0") + self.check_roundtrip("-(0b0)") + self.check_roundtrip("-0o0") + self.check_roundtrip("-(0o0)") + self.check_roundtrip("-0x0") + self.check_roundtrip("-(0x0)") + + def test_lambda_parentheses(self): + self.check_roundtrip("(lambda: int)()") + + def test_chained_comparisons(self): + self.check_roundtrip("1 < 4 <= 5") + self.check_roundtrip("a is b is c is not d") + + def test_function_arguments(self): + self.check_roundtrip("def f(): pass") + self.check_roundtrip("def f(a): pass") + self.check_roundtrip("def f(b = 2): pass") + self.check_roundtrip("def f(a, b): pass") + self.check_roundtrip("def f(a, b = 2): pass") + self.check_roundtrip("def f(a = 5, b = 2): pass") + self.check_roundtrip("def f(*args, **kwargs): pass") + if six.PY3: + self.check_roundtrip("def f(*, a = 1, b = 2): pass") + self.check_roundtrip("def f(*, a = 1, b): pass") + self.check_roundtrip("def f(*, a, b = 2): pass") + self.check_roundtrip("def f(a, b = None, *, c, **kwds): pass") + self.check_roundtrip("def f(a=2, *args, c=5, d, **kwds): pass") + + def test_relative_import(self): + self.check_roundtrip(relative_import) + + def test_import_many(self): + self.check_roundtrip(import_many) + + @unittest.skipUnless(six.PY3, "Only for Python 3") + def test_nonlocal(self): + self.check_roundtrip(nonlocal_ex) + + @unittest.skipUnless(six.PY3, "Only for Python 3") + def test_raise_from(self): + self.check_roundtrip(raise_from) + + def test_bytes(self): + self.check_roundtrip("b'123'") + + @unittest.skipIf(sys.version_info < (3, 6), "Not supported < 3.6") + def test_formatted_value(self): + self.check_roundtrip('f"{value}"') + self.check_roundtrip('f"{value!s}"') + self.check_roundtrip('f"{value:4}"') + self.check_roundtrip('f"{value!s:4}"') + + @unittest.skipIf(sys.version_info < (3, 6), "Not supported < 3.6") + def test_joined_str(self): + self.check_roundtrip('f"{key}={value!s}"') + self.check_roundtrip('f"{key}={value!r}"') + self.check_roundtrip('f"{key}={value!a}"') + + @unittest.skipIf(sys.version_info != (3, 6, 0), "Only supported on 3.6.0") + def test_joined_str_361(self): + self.check_roundtrip('f"{key:4}={value!s}"') + self.check_roundtrip('f"{key:02}={value!r}"') + self.check_roundtrip('f"{key:6}={value!a}"') + self.check_roundtrip('f"{key:4}={value:#06x}"') + self.check_roundtrip('f"{key:02}={value:#06x}"') + self.check_roundtrip('f"{key:6}={value:#06x}"') + self.check_roundtrip('f"{key:4}={value!s:#06x}"') + self.check_roundtrip('f"{key:4}={value!r:#06x}"') + self.check_roundtrip('f"{key:4}={value!a:#06x}"') + + @unittest.skipUnless(six.PY2, "Only for Python 2") + def test_repr(self): + self.check_roundtrip(a_repr) + + @unittest.skipUnless(sys.version_info[:2] >= (3, 6), "Only for Python 3.6 or greater") + def test_complex_f_string(self): + self.check_roundtrip(complex_f_string) + + @unittest.skipUnless(six.PY3, "Only for Python 3") + def test_annotations(self): + self.check_roundtrip("def f(a : int): pass") + self.check_roundtrip("def f(a: int = 5): pass") + self.check_roundtrip("def f(*args: [int]): pass") + self.check_roundtrip("def f(**kwargs: dict): pass") + self.check_roundtrip("def f() -> None: pass") + + @unittest.skipIf(sys.version_info < (2, 7), "Not supported < 2.7") + def test_set_literal(self): + self.check_roundtrip("{'a', 'b', 'c'}") + + @unittest.skipIf(sys.version_info < (2, 7), "Not supported < 2.7") + def test_set_comprehension(self): + self.check_roundtrip("{x for x in range(5)}") + + @unittest.skipIf(sys.version_info < (2, 7), "Not supported < 2.7") + def test_dict_comprehension(self): + self.check_roundtrip("{x: x*x for x in range(10)}") + + @unittest.skipIf(sys.version_info < (3, 6), "Not supported < 3.6") + def test_dict_with_unpacking(self): + self.check_roundtrip("{**x}") + self.check_roundtrip("{a: b, **x}") + + @unittest.skipIf(sys.version_info < (3, 6), "Not supported < 3.6") + def test_async_comp_and_gen_in_async_function(self): + self.check_roundtrip(async_comprehensions_and_generators) + + @unittest.skipIf(sys.version_info < (3, 7), "Not supported < 3.7") + def test_async_comprehension(self): + self.check_roundtrip("{i async for i in aiter() if i % 2}") + self.check_roundtrip("[i async for i in aiter() if i % 2]") + self.check_roundtrip("{i: -i async for i in aiter() if i % 2}") + + @unittest.skipIf(sys.version_info < (3, 7), "Not supported < 3.7") + def test_async_generator_expression(self): + self.check_roundtrip("(i ** 2 async for i in agen())") + self.check_roundtrip("(i - 1 async for i in agen() if i % 2)") + + def test_class_decorators(self): + self.check_roundtrip(class_decorator) + + @unittest.skipUnless(six.PY3, "Only for Python 3") + def test_class_definition(self): + self.check_roundtrip("class A(metaclass=type, *[], **{}): pass") + + def test_elifs(self): + self.check_roundtrip(elif1) + self.check_roundtrip(elif2) + + def test_try_except_finally(self): + self.check_roundtrip(try_except_finally) + + @unittest.skipUnless(six.PY3, "Only for Python 3") + def test_starred_assignment(self): + self.check_roundtrip("a, *b, c = seq") + self.check_roundtrip("a, (*b, c) = seq") + self.check_roundtrip("a, *b[0], c = seq") + self.check_roundtrip("a, *(b, c) = seq") + + @unittest.skipIf(sys.version_info < (3, 6), "Not supported < 3.6") + def test_variable_annotation(self): + self.check_roundtrip("a: int") + self.check_roundtrip("a: int = 0") + self.check_roundtrip("a: int = None") + self.check_roundtrip("some_list: List[int]") + self.check_roundtrip("some_list: List[int] = []") + self.check_roundtrip("t: Tuple[int, ...] = (1, 2, 3)") + self.check_roundtrip("(a): int") + self.check_roundtrip("(a): int = 0") + self.check_roundtrip("(a): int = None") + + def test_with_simple(self): + self.check_roundtrip(with_simple) + + def test_with_as(self): + self.check_roundtrip(with_as) + + @unittest.skipIf(sys.version_info < (2, 7), "Not supported < 2.7") + def test_with_two_items(self): + self.check_roundtrip(with_two_items) + + @unittest.skipIf(sys.version_info < (3, 5), "Not supported < 3.5") + def test_async_function_def(self): + self.check_roundtrip(async_function_def) + + @unittest.skipIf(sys.version_info < (3, 5), "Not supported < 3.5") + def test_async_for(self): + self.check_roundtrip(async_for) + + @unittest.skipIf(sys.version_info < (3, 5), "Not supported < 3.5") + def test_async_with(self): + self.check_roundtrip(async_with) + + @unittest.skipIf(sys.version_info < (3, 5), "Not supported < 3.5") + def test_async_with_as(self): + self.check_roundtrip(async_with_as) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/tests/test_dump.py new/astunparse-1.6.2/tests/test_dump.py --- old/astunparse-1.5.0/tests/test_dump.py 1970-01-01 01:00:00.000000000 +0100 +++ new/astunparse-1.6.2/tests/test_dump.py 2018-09-30 23:12:48.000000000 +0200 @@ -0,0 +1,24 @@ +import ast +import re +import sys +if sys.version_info < (2, 7): + import unittest2 as unittest +else: + import unittest + +import astunparse +from tests.common import AstunparseCommonTestCase + +class DumpTestCase(AstunparseCommonTestCase, unittest.TestCase): + + def assertASTEqual(self, dump1, dump2): + # undo the pretty-printing + dump1 = re.sub(r"(?<=[\(\[])\n\s+", "", dump1) + dump1 = re.sub(r"\n\s+", " ", dump1) + self.assertEqual(dump1, dump2) + + def check_roundtrip(self, code1, filename="internal", mode="exec"): + ast_ = compile(str(code1), filename, mode, ast.PyCF_ONLY_AST) + dump1 = astunparse.dump(ast_) + dump2 = ast.dump(ast_) + self.assertASTEqual(dump1, dump2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astunparse-1.5.0/tests/test_unparse.py new/astunparse-1.6.2/tests/test_unparse.py --- old/astunparse-1.5.0/tests/test_unparse.py 1970-01-01 01:00:00.000000000 +0100 +++ new/astunparse-1.6.2/tests/test_unparse.py 2018-09-30 23:12:48.000000000 +0200 @@ -0,0 +1,20 @@ +import ast +import sys +if sys.version_info < (2, 7): + import unittest2 as unittest +else: + import unittest + +import astunparse +from tests.common import AstunparseCommonTestCase + +class UnparseTestCase(AstunparseCommonTestCase, unittest.TestCase): + + def assertASTEqual(self, ast1, ast2): + self.assertEqual(ast.dump(ast1), ast.dump(ast2)) + + def check_roundtrip(self, code1, filename="internal", mode="exec"): + ast1 = compile(str(code1), filename, mode, ast.PyCF_ONLY_AST) + code2 = astunparse.unparse(ast1) + ast2 = compile(code2, filename, mode, ast.PyCF_ONLY_AST) + self.assertASTEqual(ast1, ast2)