Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-gast for openSUSE:Factory 
checked in at 2024-08-01 22:03:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-gast (Old)
 and      /work/SRC/openSUSE:Factory/.python-gast.new.7232 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-gast"

Thu Aug  1 22:03:14 2024 rev:12 rq:1189024 version:0.6.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-gast/python-gast.changes  2024-07-02 
18:14:42.423593071 +0200
+++ /work/SRC/openSUSE:Factory/.python-gast.new.7232/python-gast.changes        
2024-08-01 22:03:15.213556705 +0200
@@ -1,0 +2,17 @@
+Mon Jul 22 09:49:36 UTC 2024 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 0.6.0
+  * Harmonize gast.dump behavior across versions, following py3.13 behavior
+- from version 0.5.5
+  * Provide a bug and security bug section in the README
+  * Upgrade to py3.13 support
+  * Slightly speedup gast node creation
+  * Document ExceptHandler.name change
+  * Optimize node constructors
+  * Update unparser for py 3.12 and setup minimal testing
+  * Reflect AST changes to README
+  * Support py 3.12 type parameters
+  * Update CI configuration for python 3.12 (and 2.7!)
+  * Support Type aliases from Python 3.12
+
+-------------------------------------------------------------------

Old:
----
  gast-0.5.4.tar.gz

New:
----
  gast-0.6.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-gast.spec ++++++
--- /var/tmp/diff_new_pack.K4tSDV/_old  2024-08-01 22:03:15.909585415 +0200
+++ /var/tmp/diff_new_pack.K4tSDV/_new  2024-08-01 22:03:15.909585415 +0200
@@ -20,7 +20,7 @@
 %define srcname gast
 Name:           python-gast
 # only update when python-pythran is compatible
-Version:        0.5.4
+Version:        0.6.0
 Release:        0
 Summary:        Python AST that abstracts the underlying Python version
 License:        BSD-3-Clause

++++++ gast-0.5.4.tar.gz -> gast-0.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/.github/workflows/core.yml 
new/gast-0.6.0/.github/workflows/core.yml
--- old/gast-0.5.4/.github/workflows/core.yml   2023-04-29 21:35:43.000000000 
+0200
+++ new/gast-0.6.0/.github/workflows/core.yml   2024-06-27 22:30:35.000000000 
+0200
@@ -11,7 +11,7 @@
   build:
     strategy:
       matrix:
-          python-version: ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11", 
"3.12-dev"]
+          python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", 
"3.13.0-beta.1"]
           include:
             - python-version: 3.6
               os: ubuntu-20.04
@@ -26,6 +26,7 @@
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
+        pip install setuptools
         pip install pytest
     - name: Setup
       run: |
@@ -33,3 +34,24 @@
     - name: Testing sequential
       run: |
         pytest
+
+
+  build-27:
+    runs-on: ubuntu-20.04
+    container:
+      image: python:2.7.18-buster
+    env:
+      py27: 2.7
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v3
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install pytest
+      - name: Setup
+        run: |
+          python setup.py install
+      - name: Testing sequential
+        run: |
+          pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/README.rst new/gast-0.6.0/README.rst
--- old/gast-0.5.4/README.rst   2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/README.rst   2024-06-27 22:30:35.000000000 +0200
@@ -64,6 +64,9 @@
 notable exception of ``ast.arg`` being replaced by an ``ast.Name`` with an
 ``ast.Param`` context.
 
+The ``name`` field of ``ExceptHandler`` is represented as an ``ast.Name`` with
+an ``ast.Store`` context and not a ``str``.
+
 For minor version before 3.9, please note that ``ExtSlice`` and ``Index`` are
 not used.
 
@@ -138,20 +141,22 @@
 
         stmt = FunctionDef(identifier name, arguments args,
                            stmt* body, expr* decorator_list, expr? returns,
-                           string? type_comment)
+                           string? type_comment, type_param* type_params)
               | AsyncFunctionDef(identifier name, arguments args,
                                  stmt* body, expr* decorator_list, expr? 
returns,
-                                 string? type_comment)
+                                 string? type_comment, type_param* type_params)
 
               | ClassDef(identifier name,
                  expr* bases,
                  keyword* keywords,
                  stmt* body,
-                 expr* decorator_list)
+                 expr* decorator_list,
+                 type_param* type_params)
               | Return(expr? value)
 
               | Delete(expr* targets)
               | Assign(expr* targets, expr value, string? type_comment)
+              | TypeAlias(expr name, type_param* type_params, expr value)
               | AugAssign(expr target, operator op, expr value)
               -- 'simple' indicates that we annotate simple name without parens
               | AnnAssign(expr target, expr annotation, expr? value, int 
simple)
@@ -278,4 +283,22 @@
                  attributes (int lineno, int col_offset, int end_lineno, int 
end_col_offset)
 
         type_ignore = TypeIgnore(int lineno, string tag)
+
+         type_param = TypeVar(identifier name, expr? bound)
+                    | ParamSpec(identifier name)
+                    | TypeVarTuple(identifier name)
+                    attributes (int lineno, int col_offset, int end_lineno, 
int end_col_offset)
     }
+
+
+Reporting Bugs
+--------------
+
+Bugs can be reported through `GitHub issues 
<https://github.com/serge-sans-paille/gast/issues>`_.
+
+Reporting Security Issues
+-------------------------
+
+If for some reason, you think your bug is security-related and should be 
subject
+to responsible disclosure, don't hesitate to `contact the maintainer
+<mailto:[email protected]>`_ directly.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/SECURITY.rst new/gast-0.6.0/SECURITY.rst
--- old/gast-0.5.4/SECURITY.rst 1970-01-01 01:00:00.000000000 +0100
+++ new/gast-0.6.0/SECURITY.rst 2024-06-27 22:30:35.000000000 +0200
@@ -0,0 +1,7 @@
+Reporting Security Issues
+-------------------------
+
+If for some reason, you think your bug is security-related and should be 
subject
+to responsible disclosure, don't hesitate to `contact the maintainer
+<mailto:[email protected]>`_ directly.
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/gast/__init__.py 
new/gast-0.6.0/gast/__init__.py
--- old/gast-0.5.4/gast/__init__.py     2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/gast/__init__.py     2024-06-27 22:30:35.000000000 +0200
@@ -1,3 +1,3 @@
 from .gast import *
 from .version import __version__
-from ast import NodeVisitor, NodeTransformer, iter_fields, dump
+from ast import NodeVisitor, NodeTransformer, iter_fields
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/gast/ast2.py new/gast-0.6.0/gast/ast2.py
--- old/gast-0.5.4/gast/ast2.py 2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/gast/ast2.py 2024-06-27 22:30:35.000000000 +0200
@@ -22,6 +22,7 @@
             self._visit(node.decorator_list),
             None,  # returns
             None,  # type_comment
+            [],  # type_params
         )
         gast.copy_location(new_node, node)
         new_node.end_lineno = new_node.end_col_offset = None
@@ -34,6 +35,7 @@
             [],  # keywords
             self._visit(node.body),
             self._visit(node.decorator_list),
+            [],  # type_params
         )
 
         gast.copy_location(new_node, node)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/gast/ast3.py new/gast-0.6.0/gast/ast3.py
--- old/gast-0.5.4/gast/ast3.py 2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/gast/ast3.py 2024-06-27 22:30:35.000000000 +0200
@@ -82,6 +82,7 @@
                 self._visit(node.decorator_list),
                 self._visit(node.returns),
                 None,  # type_comment
+                [],  # type_params
             )
             return gast.copy_location(new_node, node)
 
@@ -93,6 +94,7 @@
                 self._visit(node.decorator_list),
                 self._visit(node.returns),
                 None,  # type_comment
+                [],  # type_params
             )
             return gast.copy_location(new_node, node)
 
@@ -223,6 +225,31 @@
             )
             return ast.copy_location(new_node, node)
 
+    if 8 <= sys.version_info.minor < 12:
+        def visit_FunctionDef(self, node):
+            new_node = gast.FunctionDef(
+                self._visit(node.name),
+                self._visit(node.args),
+                self._visit(node.body),
+                self._visit(node.decorator_list),
+                self._visit(node.returns),
+                self._visit(node.type_comment),
+                [],  # type_params
+            )
+            return gast.copy_location(new_node, node)
+
+        def visit_AsyncFunctionDef(self, node):
+            new_node = gast.AsyncFunctionDef(
+                self._visit(node.name),
+                self._visit(node.args),
+                self._visit(node.body),
+                self._visit(node.decorator_list),
+                self._visit(node.returns),
+                self._visit(node.type_comment),
+                [],  # type_params
+            )
+            return gast.copy_location(new_node, node)
+
 
 class GAstToAst3(GAstToAst):
     if sys.version_info.minor < 10:
@@ -423,6 +450,41 @@
                 self._visit(node.keywords),
             )
             return ast.copy_location(new_node, node)
+    if  5 <= sys.version_info.minor < 12:
+        def visit_ClassDef(self, node):
+            new_node = ast.ClassDef(
+                self._visit(node.name),
+                self._visit(node.bases),
+                self._visit(node.keywords),
+                self._visit(node.body),
+                self._visit(node.decorator_list),
+            )
+            return ast.copy_location(new_node, node)
+
+    if  8 <= sys.version_info.minor < 12:
+        def visit_FunctionDef(self, node):
+            new_node = ast.FunctionDef(
+                self._visit(node.name),
+                self._visit(node.args),
+                self._visit(node.body),
+                self._visit(node.decorator_list),
+                self._visit(node.returns),
+                self._visit(node.type_comment),
+            )
+            return ast.copy_location(new_node, node)
+
+        def visit_AsyncFunctionDef(self, node):
+            new_node = ast.AsyncFunctionDef(
+                self._visit(node.name),
+                self._visit(node.args),
+                self._visit(node.body),
+                self._visit(node.decorator_list),
+                self._visit(node.returns),
+                self._visit(node.type_comment),
+            )
+            return ast.copy_location(new_node, node)
+
+
 
     def visit_arguments(self, node):
         extra_args = [self._make_arg(node.vararg),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/gast/gast.py new/gast-0.6.0/gast/gast.py
--- old/gast-0.5.4/gast/gast.py 2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/gast/gast.py 2024-06-27 22:30:35.000000000 +0200
@@ -17,20 +17,29 @@
         pass
 
 
+try:
+    from ast import type_param
+except ImportError:
+    class type_param(AST):
+        pass
+
+
 def _make_node(Name, Fields, Attributes, Bases):
-    NBFields = len(Fields)
 
+    # This constructor is used a lot during conversion from ast to gast,
+    # then as the primary way to build ast nodes. So we tried to optimized it
+    # for speed and not for readability.
     def create_node(self, *args, **kwargs):
-        if args:
-            if len(args) + len([k for k in kwargs if k in Fields]) != NBFields:
-                raise TypeError(
-                    "{} constructor takes either 0 or {} mandatory arguments".
-                    format(Name, NBFields))
-            for argname, argval in zip(Fields, args):
-                setattr(self, argname, argval)
-        if kwargs:
-            for argname, argval in kwargs.items():
-                setattr(self, argname, argval)
+        if len(args) > len(Fields):
+            raise TypeError(
+                "{} constructor takes at most {} positional arguments".
+                format(Name, len(Fields)))
+
+        # it's faster to iterate rather than zipping or enumerate
+        for i in range(len(args)):
+            setattr(self, Fields[i], args[i])
+        if kwargs:  # cold branch
+            self.__dict__.update(kwargs)
 
     setattr(_sys.modules[__name__],
             Name,
@@ -51,16 +60,16 @@
 
     # stmt
     ('FunctionDef', (('name', 'args', 'body', 'decorator_list', 'returns',
-                      'type_comment'),
+                      'type_comment', 'type_params'),
                      ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',),
                      (stmt,))),
-    ('AsyncFunctionDef', (('name', 'args', 'body',
-                           'decorator_list', 'returns',
-                           'type_comment'),
+    ('AsyncFunctionDef', (('name', 'args', 'body', 'decorator_list', 'returns',
+                           'type_comment', 'type_params',),
                           ('lineno', 'col_offset',
                            'end_lineno', 'end_col_offset',),
                           (stmt,))),
-    ('ClassDef', (('name', 'bases', 'keywords', 'body', 'decorator_list',),
+    ('ClassDef', (('name', 'bases', 'keywords', 'body', 'decorator_list',
+                   'type_params',),
                   ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',),
                   (stmt,))),
     ('Return', (('value',),
@@ -72,6 +81,9 @@
     ('Assign', (('targets', 'value', 'type_comment'),
                 ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',),
                 (stmt,))),
+    ('TypeAlias', (('name', 'type_params', 'value'),
+                  ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',),
+                  (stmt,))),
     ('AugAssign', (('target', 'op', 'value',),
                    ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',),
                    (stmt,))),
@@ -340,8 +352,25 @@
 
     # type_ignore
     ('type_ignore', ((), ('lineno', 'tag'), (TypeIgnore,))),
+
+    # type_param
+    ('TypeVar', (('name', 'bound',),
+                 ('lineno', 'col_offset',
+                  'end_lineno', 'end_col_offset'),
+                 (type_param,))),
+    ('ParamSpec', (('name',),
+                 ('lineno', 'col_offset',
+                  'end_lineno', 'end_col_offset'),
+                 (type_param,))),
+    ('TypeVarTuple', (('name',),
+                 ('lineno', 'col_offset',
+                  'end_lineno', 'end_col_offset'),
+                 (type_param,))),
     )
 
+
+
+
 for name, descr in _nodes:
     _make_node(name, *descr)
 
@@ -440,3 +469,95 @@
         if 'end_lineno' in child._attributes:
             child.end_lineno = (getattr(child, 'end_lineno', 0) or 0) + n
     return node
+
+if _sys.version_info.major == 3 and _sys.version_info.minor >= 13:
+    dump = _ast.dump
+else:
+    # Code import from Lib/ast.py
+    #
+    # minor changes: getattr(x, y, ...) is None => getattr(x, y, 42) is None
+    #
+    def dump(
+        node, annotate_fields=True, include_attributes=False,
+        # *,  # removed for compatibility with python2 :-/
+        indent=None, show_empty=False,
+    ):
+        """
+        Return a formatted dump of the tree in node.  This is mainly useful for
+        debugging purposes.  If annotate_fields is true (by default),
+        the returned string will show the names and the values for fields.
+        If annotate_fields is false, the result string will be more compact by
+        omitting unambiguous field names.  Attributes such as line
+        numbers and column offsets are not dumped by default.  If this is 
wanted,
+        include_attributes can be set to true.  If indent is a non-negative
+        integer or string, then the tree will be pretty-printed with that 
indent
+        level. None (the default) selects the single line representation.
+        If show_empty is False, then empty lists and fields that are None
+        will be omitted from the output for better readability.
+        """
+        def _format(node, level=0):
+            if indent is not None:
+                level += 1
+                prefix = '\n' + indent * level
+                sep = ',\n' + indent * level
+            else:
+                prefix = ''
+                sep = ', '
+            if isinstance(node, AST):
+                cls = type(node)
+                args = []
+                args_buffer = []
+                allsimple = True
+                keywords = annotate_fields
+                for name in node._fields:
+                    try:
+                        value = getattr(node, name)
+                    except AttributeError:
+                        keywords = True
+                        continue
+                    if value is None and getattr(cls, name, 42) is None:
+                        keywords = True
+                        continue
+                    if (
+                        not show_empty
+                        and (value is None or value == [])
+                        # Special cases:
+                        # `Constant(value=None)` and 
`MatchSingleton(value=None)`
+                        and not isinstance(node, (Constant, MatchSingleton))
+                    ):
+                        args_buffer.append(repr(value))
+                        continue
+                    elif not keywords:
+                        args.extend(args_buffer)
+                        args_buffer = []
+                    value, simple = _format(value, level)
+                    allsimple = allsimple and simple
+                    if keywords:
+                        args.append('%s=%s' % (name, value))
+                    else:
+                        args.append(value)
+                if include_attributes and node._attributes:
+                    for name in node._attributes:
+                        try:
+                            value = getattr(node, name)
+                        except AttributeError:
+                            continue
+                        if value is None and getattr(cls, name, 42) is None:
+                            continue
+                        value, simple = _format(value, level)
+                        allsimple = allsimple and simple
+                        args.append('%s=%s' % (name, value))
+                if allsimple and len(args) <= 3:
+                    return '%s(%s)' % (node.__class__.__name__, ', 
'.join(args)), not args
+                return '%s(%s%s)' % (node.__class__.__name__, prefix, 
sep.join(args)), False
+            elif isinstance(node, list):
+                if not node:
+                    return '[]', True
+                return '[%s%s]' % (prefix, sep.join(_format(x, level)[0] for x 
in node)), False
+            return repr(node), True
+
+        if not isinstance(node, AST):
+            raise TypeError('expected AST, got %r' % node.__class__.__name__)
+        if indent is not None and not isinstance(indent, str):
+            indent = ' ' * indent
+        return _format(node)[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/gast/unparser.py 
new/gast-0.6.0/gast/unparser.py
--- old/gast-0.5.4/gast/unparser.py     2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/gast/unparser.py     2024-06-27 22:30:35.000000000 +0200
@@ -412,6 +412,8 @@
             self.fill("@")
             self.traverse(deco)
         self.fill("class " + node.name)
+        if hasattr(node, "type_params"):
+            self._type_params_helper(node.type_params)
         with self.delimit_if("(", ")", condition = node.bases or 
node.keywords):
             comma = False
             for e in node.bases:
@@ -443,6 +445,8 @@
             self.traverse(deco)
         def_str = fill_suffix + " " + node.name
         self.fill(def_str)
+        if hasattr(node, "type_params"):
+            self._type_params_helper(node.type_params)
         with self.delimit("(", ")"):
             self.traverse(node.args)
         if node.returns:
@@ -451,6 +455,30 @@
         with self.block(extra=self.get_type_comment(node)):
             self._write_docstring_and_traverse_body(node)
 
+    def _type_params_helper(self, type_params):
+        if type_params is not None and len(type_params) > 0:
+            with self.delimit("[", "]"):
+                self.interleave(lambda: self.write(", "), self.traverse, 
type_params)
+
+    def visit_TypeVar(self, node):
+        self.write(node.name)
+        if node.bound:
+            self.write(": ")
+            self.traverse(node.bound)
+
+    def visit_TypeVarTuple(self, node):
+        self.write("*" + node.name)
+
+    def visit_ParamSpec(self, node):
+        self.write("**" + node.name)
+
+    def visit_TypeAlias(self, node):
+        self.fill("type ")
+        self.traverse(node.name)
+        self._type_params_helper(node.type_params)
+        self.write(" = ")
+        self.traverse(node.value)
+
     def visit_For(self, node):
         self._for_helper("for ", node)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/gast/version.py 
new/gast-0.6.0/gast/version.py
--- old/gast-0.5.4/gast/version.py      2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/gast/version.py      2024-06-27 22:30:35.000000000 +0200
@@ -1 +1 @@
-__version__ = '0.5.4'
+__version__ = '0.6.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/tests/test_api.py 
new/gast-0.6.0/tests/test_api.py
--- old/gast-0.5.4/tests/test_api.py    2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/tests/test_api.py    2024-06-27 22:30:35.000000000 +0200
@@ -2,6 +2,11 @@
 
 import ast
 import gast
+import sys
+
+
+def dump(node):
+    return gast.dump(node, show_empty=True)
 
 
 class APITestCase(unittest.TestCase):
@@ -33,7 +38,7 @@
     def test_dump(self):
         code = 'lambda x: x'
         tree = gast.parse(code, mode='eval')
-        dump = gast.dump(tree)
+        zdump = dump(tree)
         norm = ("Expression(body=Lambda(args=arguments(args=[Name("
                 "id='x', ctx=Param(), "
                 "annotation=None, type_comment=None)], posonlyargs=[], "
@@ -41,16 +46,16 @@
                 "defaults=[]), body=Name(id='x', ctx=Load(), "
                 "annotation=None, type_comment=None)"
                 "))")
-        self.assertEqual(dump, norm)
+        self.assertEqual(zdump, norm)
 
     def test_walk(self):
         code = 'x + 1'
         tree = gast.parse(code, mode='eval')
-        dump = gast.dump(tree)
+        zdump = dump(tree)
         norm = ("Expression(body=BinOp(left=Name(id='x', ctx=Load(), "
                 "annotation=None, type_comment=None), op=Add(), "
                 "right=Constant(value=1, kind=None)))")
-        self.assertEqual(dump, norm)
+        self.assertEqual(zdump, norm)
         self.assertEqual(len(list(gast.walk(tree))), 6)
 
     def test_iter_fields(self):
@@ -132,7 +137,8 @@
         node1 = gast.Name('id', load, None, None)
         node2 = gast.Name('id', load, None, type_comment=None)
         with self.assertRaises(TypeError):
-            node1 = gast.Name('id')
+            node1 = gast.Name('id', 'ctx', 'annotation', 'type_comment',
+                              'random_field')
         for field in gast.Name._fields:
             self.assertEqual(getattr(node1, field), getattr(node2, field))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/tests/test_compat.py 
new/gast-0.6.0/tests/test_compat.py
--- old/gast-0.5.4/tests/test_compat.py 2023-04-29 21:35:43.000000000 +0200
+++ new/gast-0.6.0/tests/test_compat.py 2024-06-27 22:30:35.000000000 +0200
@@ -4,8 +4,16 @@
 import sys
 
 
+def dump(node):
+    return gast.dump(node, show_empty=True)
+
+
 class CompatTestCase(unittest.TestCase):
 
+    def __init__(self, *args, **kwargs):
+        unittest.TestCase.__init__(self, *args, **kwargs)
+        self.maxDiff = None
+
     if sys.version_info.major == 2:
 
         def test_FunctionDef(self):
@@ -23,8 +31,9 @@
                     "Name(id='y', ctx=Load(), "
                     "annotation=None, type_comment=None"
                     ")], ctx=Load()))], decorator_list="
-                    "[], returns=None, type_comment=None)], type_ignores=[])")
-            self.assertEqual(gast.dump(tree), norm)
+                    "[], returns=None, type_comment=None, type_params=[])], "
+                    "type_ignores=[])")
+            self.assertEqual(dump(tree), norm)
 
     else:
 
@@ -38,8 +47,9 @@
                     "), type_comment=None)], posonlyargs="
                     "[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg="
                     "None, defaults=[]), body=[Pass()], decorator_list=[], "
-                    "returns=None, type_comment=None)], type_ignores=[])")
-            self.assertEqual(gast.dump(tree), norm)
+                    "returns=None, type_comment=None, type_params=[])], "
+                    "type_ignores=[])")
+            self.assertEqual(dump(tree), norm)
 
         def test_KeywordOnlyArgument(self):
             code = 'def foo(*, x=1): pass'
@@ -50,8 +60,9 @@
                     "(id='x', ctx=Param(), annotation=None, type_comment=None"
                     ")], kw_defaults=[Constant(value=1, kind=None)], kwarg="
                     "None, defaults=[]), body=[Pass()], decorator_list=[], "
-                    "returns=None, type_comment=None)], type_ignores=[])")
-            self.assertEqual(gast.dump(tree), norm)
+                    "returns=None, type_comment=None, type_params=[])], "
+                    "type_ignores=[])")
+            self.assertEqual(dump(tree), norm)
 
         if sys.version_info.minor >= 6:
 
@@ -67,7 +78,7 @@
                         "ctx=Load(), annotation=None, type_comment=None), "
                         "conversion=-1, format_spec=None)]))], "
                         "type_ignores=[])")
-                self.assertEqual(gast.dump(tree), norm)
+                self.assertEqual(dump(tree), norm)
 
             def test_JoinedStr(self):
                 code = 'e = 1; f"e = {e}"'
@@ -82,7 +93,7 @@
                         "annotation=None, type_comment=None), "
                         "conversion=-1, format_spec=None)]))], "
                         "type_ignores=[])")
-                self.assertEqual(gast.dump(tree), norm)
+                self.assertEqual(dump(tree), norm)
 
         if sys.version_info.minor >= 8:
 
@@ -94,9 +105,9 @@
                         "args=[], posonlyargs=[], vararg=None, kwonlyargs=[], "
                         "kw_defaults=[], kwarg=None, defaults=[]), body=["
                         "Pass()], decorator_list=[], returns=None, "
-                        "type_comment=None)], type_ignores="
+                        "type_comment=None, type_params=[])], type_ignores="
                         "[TypeIgnore(lineno=1, tag='[excuse]')])")
-                self.assertEqual(gast.dump(tree), norm)
+                self.assertEqual(dump(tree), norm)
 
             def test_PosonlyArgs(self):
                 code = 'def foo(a, /, b): pass'
@@ -108,9 +119,9 @@
                         "ctx=Param(), annotation=None, type_comment=None)], "
                         "vararg=None, kwonlyargs=[], kw_defaults=[], "
                         "kwarg=None, defaults=[]), body=[Pass()], "
-                        "decorator_list=[], returns=None, type_comment=None)"
-                        "], type_ignores=[])")
-                self.assertEqual(gast.dump(tree), norm)
+                        "decorator_list=[], returns=None, type_comment=None, "
+                        "type_params=[])], type_ignores=[])")
+                self.assertEqual(dump(tree), norm)
 
             def test_NamedExpr(self):
                 code = '(x := 1) '
@@ -120,7 +131,7 @@
                         " ctx=Store(), annotation=None, type_comment=None), "
                         "value=Constant(value=1, kind=None)))], type_ignores="
                         "[])")
-                self.assertEqual(gast.dump(tree), norm)
+                self.assertEqual(dump(tree), norm)
 
             if sys.version_info.minor >= 10:
 
@@ -135,10 +146,9 @@
                             "[Expr(value=Constant(value=Ellipsis, kind=None))]"
                             ")])], type_ignores=[])"
                             )
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
                 def test_MatchSingleton(self):
-                    self.maxDiff = None
                     code = 'match v:\n  case None:...'
                     tree = gast.parse(code)
                     compile(gast.gast_to_ast(tree), '<test>', 'exec')
@@ -147,7 +157,7 @@
                             "match_case(pattern=MatchSingleton(value=None), "
                             "guard=None, body=[Expr(value=Constant(value="
                             "Ellipsis, kind=None))])])], type_ignores=[])")
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
                 def test_MatchSequence(self):
                     code = 'match v:\n  case a, b:...'
@@ -160,7 +170,7 @@
                             "=None, name='b')]), guard=None, body=[Expr(value"
                             "=Constant(value=Ellipsis, kind=None))])])], "
                             "type_ignores=[])")
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
                 def test_MatchMapping(self):
                     code = 'match v:\n  case {1: a}:...'
@@ -173,7 +183,7 @@
                             "=None, name='a')], rest=None), guard=None, body="
                             "[Expr(value=Constant(value=Ellipsis, kind=None))]"
                             ")])], type_ignores=[])")
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
                 def test_MatchClass(self):
                     code = 'match v:\n  case Cls(attr=1):...'
@@ -187,7 +197,7 @@
                             "=[MatchValue(value=Constant(value=1, kind=None))"
                             "]), guard=None, body=[Expr(value=Constant(value="
                             "Ellipsis, kind=None))])])], type_ignores=[])")
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
                 def test_MatchStar(self):
                     code = 'match v:\n  case [1, *other]:...'
@@ -200,7 +210,7 @@
                             "MatchStar(name='other')]), guard=None, body="
                             "[Expr(value=Constant(value=Ellipsis, kind=None)"
                             ")])])], type_ignores=[])")
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
                 def test_MatchAs(self):
                     code = 'match v:\n  case 1, other:...'
@@ -213,7 +223,7 @@
                             "MatchAs(pattern=None, name='other')]), guard=None"
                             ", body=[Expr(value=Constant(value=Ellipsis, kind"
                             "=None))])])], type_ignores=[])")
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
                 def test_MatchOr(self):
                     code = 'match v:\n  case 1 | 2:...'
@@ -226,7 +236,7 @@
                             "value=Constant(value=2, kind=None))]), guard="
                             "None, body=[Expr(value=Constant(value=Ellipsis, "
                             "kind=None))])])], type_ignores=[])")
-                    self.assertEqual(gast.dump(tree), norm)
+                    self.assertEqual(dump(tree), norm)
 
 
                 if sys.version_info.minor >= 11:
@@ -251,7 +261,7 @@
                 compile(gast.gast_to_ast(tree), '<test>', 'exec')
                 norm = ("Module(body=[Expr(value=Constant(value=b'0012', "
                         "kind=None))], type_ignores=[])")
-                self.assertEqual(gast.dump(tree), norm)
+                self.assertEqual(dump(tree), norm)
 
     # common
 
@@ -263,7 +273,7 @@
                 "type=Name(id='e', ctx=Load(), annotation=None, "
                 "type_comment=None), name=None, body=[Pass()])]"
                 ", orelse=[Pass()], finalbody=[])], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+        self.assertEqual(dump(tree), norm)
 
     def test_TryExceptNamed(self):
         code = 'try:pass\nexcept e as f:pass\nelse:pass'
@@ -274,7 +284,7 @@
                 "type_comment=None), name=Name(id='f', ctx="
                 "Store(), annotation=None, type_comment=None), body=[Pass()])]"
                 ", orelse=[Pass()], finalbody=[])], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+        self.assertEqual(dump(tree), norm)
 
     def test_Raise(self):
         codes = ('raise Exception',
@@ -315,10 +325,9 @@
         for code, norm in zip(codes, norms):
             tree = gast.parse(code)
             compile(gast.gast_to_ast(tree), '<test>', 'exec')
-            self.assertEqual(gast.dump(tree), norm)
+            self.assertEqual(dump(tree), norm)
 
     def test_Call(self):
-        self.maxDiff = None
         code = 'foo(x, y=1, *args, **kwargs)'
         tree = gast.parse(code)
         compile(gast.gast_to_ast(tree), '<test>', 'exec')
@@ -331,7 +340,7 @@
                 "arg='y', value=Constant(value=1, kind=None)), keyword(arg"
                 "=None, value=Name(id='kwargs', ctx=Load(), annotation=None, "
                 "type_comment=None))]))], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+        self.assertEqual(dump(tree), norm)
 
     def test_With(self):
         code = 'with open("any"): pass'
@@ -342,7 +351,7 @@
                 "type_comment=None), args=[Constant(value='any', "
                 "kind=None)], keywords=[]), optional_vars=None)], body=["
                 "Pass()], type_comment=None)], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+        self.assertEqual(dump(tree), norm)
 
     def test_TryFinally(self):
         code = 'try:pass\nfinally:pass'
@@ -350,7 +359,7 @@
         compile(gast.gast_to_ast(tree), '<test>', 'exec')
         norm = ("Module(body=[Try(body=[Pass()], handlers=[], orelse=[], "
                 "finalbody=[Pass()])], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+        self.assertEqual(dump(tree), norm)
 
     def test_star_argument(self):
         code = 'def foo(*a): pass'
@@ -361,8 +370,8 @@
                 "annotation=None, type_comment=None), "
                 "kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), "
                 "body=[Pass()], decorator_list=[], returns=None, "
-                "type_comment=None)], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+                "type_comment=None, type_params=[])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
 
     def test_keyword_argument(self):
         code = 'def foo(**a): pass'
@@ -372,9 +381,9 @@
                 "posonlyargs=[], vararg=None, kwonlyargs=[], kw_defaults=[], "
                 "kwarg=Name(id='a', ctx=Param(), annotation=None, "
                 "type_comment=None), defaults=[]), body=[Pass()], "
-                "decorator_list=[], returns=None, type_comment=None)], "
-                "type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+                "decorator_list=[], returns=None, type_comment=None, "
+                "type_params=[])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
 
     def test_Index(self):
         code = 'def foo(a): a[1]'
@@ -386,12 +395,11 @@
                 ", kwarg=None, defaults=[]), body=[Expr(value=Subscript(value="
                 "Name(id='a', ctx=Load(), annotation=None, type_comment=None)"
                 ", slice=Constant(value=1, kind=None), ctx=Load()"
-                "))], decorator_list=[], returns=None, type_comment=None)]"
-                ", type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+                "))], decorator_list=[], returns=None, type_comment=None, "
+                "type_params=[])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
 
     def test_ExtSlice(self):
-        self.maxDiff = None
         code = 'def foo(a): a[:,:]'
         tree = gast.parse(code)
         compile(gast.gast_to_ast(tree), '<test>', 'exec')
@@ -403,11 +411,10 @@
                 ", slice=Tuple(elts=[Slice(lower=None, upper=None, step="
                 "None), Slice(lower=None, upper=None, step=None)], ctx=Load())"
                 ", ctx=Load()))], decorator_list=[], returns=None, "
-                "type_comment=None)], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+                "type_comment=None, type_params=[])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
 
     def test_ExtSlices(self):
-        self.maxDiff = None
         code = 'def foo(a): a[1,:]'
         tree = gast.parse(code)
         compile(gast.gast_to_ast(tree), '<test>', 'exec')
@@ -419,11 +426,10 @@
                 ", slice=Tuple(elts=[Constant(value=1, kind="
                 "None), Slice(lower=None, upper=None, step=None)], ctx=Load())"
                 ", ctx=Load()))], decorator_list=[], returns=None, "
-                "type_comment=None)], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+                "type_comment=None, type_params=[])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
 
     def test_Ellipsis(self):
-        self.maxDiff = None
         code = 'def foo(a): a[...]'
         tree = gast.parse(code)
         compile(gast.gast_to_ast(tree), '<test>', 'exec')
@@ -433,12 +439,11 @@
                 ", kwarg=None, defaults=[]), body=[Expr(value=Subscript(value="
                 "Name(id='a', ctx=Load(), annotation=None, type_comment=None)"
                 ", slice=Constant(value=Ellipsis, kind=None), ctx=Load()))], "
-                "decorator_list=[], returns=None, type_comment="
-                "None)], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+                "decorator_list=[], returns=None, type_comment=None, "
+                "type_params=[])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
 
     def test_ExtSliceEllipsis(self):
-        self.maxDiff = None
         code = 'def foo(a): a[1, ...]'
         tree = gast.parse(code)
         compile(gast.gast_to_ast(tree), '<test>', 'exec')
@@ -450,8 +455,8 @@
                 ", slice=Tuple(elts=[Constant(value=1, kind=None)"
                 ", Constant(value=Ellipsis, kind=None)], ctx=Load()), ctx="
                 "Load()))], decorator_list=[], returns=None, type_comment="
-                "None)], type_ignores=[])")
-        self.assertEqual(gast.dump(tree), norm)
+                "None, type_params=[])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
 
 
 if __name__ == '__main__':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/tests/test_py3_12.py 
new/gast-0.6.0/tests/test_py3_12.py
--- old/gast-0.5.4/tests/test_py3_12.py 1970-01-01 01:00:00.000000000 +0100
+++ new/gast-0.6.0/tests/test_py3_12.py 2024-06-27 22:30:35.000000000 +0200
@@ -0,0 +1,71 @@
+import unittest
+
+import ast
+import gast
+import sys
+
+def dump(node):
+    return gast.dump(node, show_empty=True)
+
+
+class Python3_12TestCase(unittest.TestCase):
+
+    def __init__(self, *args, **kwargs):
+        unittest.TestCase.__init__(self, *args, **kwargs)
+        self.maxDiff = None
+
+    def test_type_alias(self):
+        code = "type Point = tuple[float, float]"
+        tree = gast.parse(code)
+        compile(gast.gast_to_ast(tree), '<test>', 'exec')
+        norm = ("Module(body=[TypeAlias(name=Name(id='Point', ctx=Store(),"
+                " annotation=None, type_comment=None), type_params=[], "
+                "value=Subscript(value=Name(id='tuple', ctx=Load(), "
+                "annotation=None, type_comment=None), slice=Tuple(elts=["
+                "Name(id='float', ctx=Load(), annotation=None, "
+                "type_comment=None), Name(id='float', ctx=Load(), "
+                "annotation=None, type_comment=None)], ctx=Load()), "
+                "ctx=Load()))], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
+
+    def test_generic_type_alias(self):
+        code = "type Point[T] = tuple[T, float]"
+        tree = gast.parse(code)
+        compile(gast.gast_to_ast(tree), '<test>', 'exec')
+        norm = ("Module(body=[TypeAlias(name=Name(id='Point', ctx=Store(), "
+                "annotation=None, type_comment=None), type_params=[TypeVar("
+                "name='T', bound=None)], value=Subscript(value=Name(id='tuple'"
+                ", ctx=Load(), annotation=None, type_comment=None), "
+                "slice=Tuple(elts=[Name(id='T', ctx=Load(), annotation=None, "
+                "type_comment=None), Name(id='float', ctx=Load(), "
+                "annotation=None, type_comment=None)], ctx=Load()), ctx=Load()"
+                "))], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
+
+    def test_generic_function(self):
+        code = "def foo[T]():..."
+        tree = gast.parse(code)
+        compile(gast.gast_to_ast(tree), '<test>', 'exec')
+        norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[], "
+                "posonlyargs=[], vararg=None, kwonlyargs=[], kw_defaults=[], "
+                "kwarg=None, defaults=[]), body=[Expr(value=Constant(value="
+                "Ellipsis, kind=None))], decorator_list=[], returns=None, "
+                "type_comment=None, type_params=[TypeVar(name='T', "
+                "bound=None)])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
+
+    def test_generic_class(self):
+        code = "class foo[T]:..."
+        tree = gast.parse(code)
+        compile(gast.gast_to_ast(tree), '<test>', 'exec')
+        norm = ("Module(body=[ClassDef(name='foo', bases=[], keywords=[], "
+                "body=[Expr(value=Constant(value=Ellipsis, kind=None))], "
+                "decorator_list=[], type_params=[TypeVar(name='T', bound=None)"
+                "])], type_ignores=[])")
+        self.assertEqual(dump(tree), norm)
+
+if sys.version_info < (3, 12):
+    del Python3_12TestCase
+
+if __name__ == '__main__':
+    unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gast-0.5.4/tests/test_unparser.py 
new/gast-0.6.0/tests/test_unparser.py
--- old/gast-0.5.4/tests/test_unparser.py       1970-01-01 01:00:00.000000000 
+0100
+++ new/gast-0.6.0/tests/test_unparser.py       2024-06-27 22:30:35.000000000 
+0200
@@ -0,0 +1,37 @@
+import unittest
+
+import ast
+import gast
+import sys
+
+
+class UnparserTestCase(unittest.TestCase):
+
+    def __init__(self, *args, **kwargs):
+        unittest.TestCase.__init__(self, *args, **kwargs)
+        self.maxDiff = None
+
+    def assertUnparse(self, code):
+        normalized_code = ast.unparse(ast.parse(code))
+        tree = gast.parse(normalized_code)
+        compile(gast.gast_to_ast(tree), '<test>', 'exec')
+        unparsed = gast.unparse(tree)
+        self.assertEqual(normalized_code, unparsed)
+
+    def test_FunctionDef(self):
+        self.assertUnparse('def foo(x, y): return x, y')
+
+    def test_BinaryOp(self):
+        self.assertUnparse('1 + 3')
+
+    if sys.version_info >= (3, 12):
+
+        def test_TypeParameter(self):
+            self.assertUnparse('type x[T] = list[T]')
+
+
+if sys.version_info < (3, 9):
+    del UnparserTestCase
+
+if __name__ == '__main__':
+    unittest.main()

Reply via email to