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)


Reply via email to