pax_global_header00006660000000000000000000000064146373457530014533gustar00rootroot0000000000000052 comment=20113b4a6a26ca237a3b1a44a92d73108f4a8dd8 gast-0.6.0/000077500000000000000000000000001463734575300124745ustar00rootroot00000000000000gast-0.6.0/.github/000077500000000000000000000000001463734575300140345ustar00rootroot00000000000000gast-0.6.0/.github/workflows/000077500000000000000000000000001463734575300160715ustar00rootroot00000000000000gast-0.6.0/.github/workflows/core.yml000066400000000000000000000023761463734575300175540ustar00rootroot00000000000000name: core on: push: branches: - master pull_request: branches: - master jobs: build: strategy: matrix: 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 runs-on: ${{ matrix.os || 'ubuntu-latest' }} steps: - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install setuptools pip install pytest - name: Setup run: | python setup.py install - 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 gast-0.6.0/.gitignore000066400000000000000000000001771463734575300144710ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # Distribution / packaging build/ dist/ *.egg-info/ gast-0.6.0/LICENSE000066400000000000000000000027221463734575300135040ustar00rootroot00000000000000Copyright (c) 2016, Serge Guelton All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of HPCProject, Serge Guelton nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gast-0.6.0/MANIFEST.in000066400000000000000000000000551463734575300142320ustar00rootroot00000000000000recursive-include tests *.py include LICENSE gast-0.6.0/README.rst000066400000000000000000000262721463734575300141740ustar00rootroot00000000000000GAST, daou naer! ================ A generic AST to represent Python2 and Python3's Abstract Syntax Tree(AST). GAST provides a compatibility layer between the AST of various Python versions, as produced by ``ast.parse`` from the standard ``ast`` module. Basic Usage ----------- .. code:: python >>> import ast, gast >>> code = open('file.py').read() >>> tree = ast.parse(code) >>> gtree = gast.ast_to_gast(tree) >>> ... # process gtree >>> tree = gast.gast_to_ast(gtree) >>> ... # do stuff specific to tree API --- ``gast`` provides the same API as the ``ast`` module. All functions and classes from the ``ast`` module are also available in the ``gast`` module, and work accordingly on the ``gast`` tree. Three notable exceptions: 1. ``gast.parse`` directly produces a GAST node. It's equivalent to running ``gast.ast_to_gast`` on the output of ``ast.parse``. 2. ``gast.dump`` dumps the ``gast`` common representation, not the original one. 3. ``gast.gast_to_ast`` and ``gast.ast_to_gast`` can be used to convert from one ast to the other, back and forth. Version Compatibility --------------------- GAST is tested using ``tox`` and Travis on the following Python versions: - 2.7 - 3.4 - 3.5 - 3.6 - 3.7 - 3.8 - 3.9 - 3.10 - 3.11 AST Changes ----------- Python3 ******* The AST used by GAST is the same as the one used in Python3.9, with the 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. For minor version before 3.8, please note that ``Ellipsis``, ``Num``, ``Str``, ``Bytes`` and ``NamedConstant`` are represented as ``Constant``. Python2 ******* To cope with Python3 features, several nodes from the Python2 AST are extended with some new attributes/children, or represented by different nodes - ``ModuleDef`` nodes have a ``type_ignores`` attribute. - ``FunctionDef`` nodes have a ``returns`` attribute and a ``type_comment`` attribute. - ``ClassDef`` nodes have a ``keywords`` attribute. - ``With``'s ``context_expr`` and ``optional_vars`` fields are hold in a ``withitem`` object. - ``For`` nodes have a ``type_comment`` attribute. - ``Raise``'s ``type``, ``inst`` and ``tback`` fields are hold in a single ``exc`` field, using the transformation ``raise E, V, T => raise E(V).with_traceback(T)``. - ``TryExcept`` and ``TryFinally`` nodes are merged in the ``Try`` node. - ``arguments`` nodes have a ``kwonlyargs`` and ``kw_defaults`` attributes. - ``Call`` nodes loose their ``starargs`` attribute, replaced by an argument wrapped in a ``Starred`` node. They also loose their ``kwargs`` attribute, wrapped in a ``keyword`` node with the identifier set to ``None``, as done in Python3. - ``comprehension`` nodes have an ``async`` attribute (that is always set to 0). - ``Ellipsis``, ``Num`` and ``Str`` nodes are represented as ``Constant``. - ``Subscript`` which don't have any ``Slice`` node as ``slice`` attribute (and ``Ellipsis`` are not ``Slice`` nodes) no longer hold an ``ExtSlice`` but an ``Index(Tuple(...))`` instead. Pit Falls ********* - In Python3, ``None``, ``True`` and ``False`` are parsed as ``Constant`` while they are parsed as regular ``Name`` in Python2. ASDL **** This closely matches the one from https://docs.python.org/3/library/ast.html#abstract-grammar, with a few trade-offs to cope with legacy ASTs. .. code:: -- ASDL's six builtin types are identifier, int, string, bytes, object, singleton module Python { mod = Module(stmt* body, type_ignore *type_ignores) | Interactive(stmt* body) | Expression(expr body) | FunctionType(expr* argtypes, expr returns) -- not really an actual node but useful in Jython's typesystem. | Suite(stmt* body) stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params) | AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params) | ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, 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) -- not sure if bool is allowed, can always use int | Print(expr? dest, expr* values, bool nl) -- use 'orelse' because else is a keyword in target languages | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment) | While(expr test, stmt* body, stmt* orelse) | If(expr test, stmt* body, stmt* orelse) | With(withitem* items, stmt* body, string? type_comment) | AsyncWith(withitem* items, stmt* body, string? type_comment) | Match(expr subject, match_case* cases) | Raise(expr? exc, expr? cause) | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) | TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) | Assert(expr test, expr? msg) | Import(alias* names) | ImportFrom(identifier? module, alias* names, int? level) -- Doesn't capture requirement that locals must be -- defined if globals is -- still supports use as a function! | Exec(expr body, expr? globals, expr? locals) | Global(identifier* names) | Nonlocal(identifier* names) | Expr(expr value) | Pass | Break | Continue -- XXX Jython will be different -- col_offset is the byte offset in the utf8 string the parser uses attributes (int lineno, int col_offset) -- BoolOp() can use left & right? expr = BoolOp(boolop op, expr* values) | NamedExpr(expr target, expr value) | BinOp(expr left, operator op, expr right) | UnaryOp(unaryop op, expr operand) | Lambda(arguments args, expr body) | IfExp(expr test, expr body, expr orelse) | Dict(expr* keys, expr* values) | Set(expr* elts) | ListComp(expr elt, comprehension* generators) | SetComp(expr elt, comprehension* generators) | DictComp(expr key, expr value, comprehension* generators) | GeneratorExp(expr elt, comprehension* generators) -- the grammar constrains where yield expressions can occur | Await(expr value) | Yield(expr? value) | YieldFrom(expr value) -- need sequences for compare to distinguish between -- x < 4 < 3 and (x < 4) < 3 | Compare(expr left, cmpop* ops, expr* comparators) | Call(expr func, expr* args, keyword* keywords) | Repr(expr value) | FormattedValue(expr value, int? conversion, expr? format_spec) | JoinedStr(expr* values) | Constant(constant value, string? kind) -- the following expression can appear in assignment context | Attribute(expr value, identifier attr, expr_context ctx) | Subscript(expr value, slice slice, expr_context ctx) | Starred(expr value, expr_context ctx) | Name(identifier id, expr_context ctx, expr? annotation, string? type_comment) | List(expr* elts, expr_context ctx) | Tuple(expr* elts, expr_context ctx) -- col_offset is the byte offset in the utf8 string the parser uses attributes (int lineno, int col_offset) expr_context = Load | Store | Del | AugLoad | AugStore | Param slice = Slice(expr? lower, expr? upper, expr? step) | ExtSlice(slice* dims) | Index(expr value) boolop = And | Or operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | RShift | BitOr | BitXor | BitAnd | FloorDiv unaryop = Invert | Not | UAdd | USub cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn comprehension = (expr target, expr iter, expr* ifs, int is_async) excepthandler = ExceptHandler(expr? type, expr? name, stmt* body) attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) arguments = (expr* args, expr* posonlyargs, expr? vararg, expr* kwonlyargs, expr* kw_defaults, expr? kwarg, expr* defaults) -- keyword arguments supplied to call (NULL identifier for **kwargs) keyword = (identifier? arg, expr value) -- import name with optional 'as' alias. alias = (identifier name, identifier? asname) attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) withitem = (expr context_expr, expr? optional_vars) match_case = (pattern pattern, expr? guard, stmt* body) pattern = MatchValue(expr value) | MatchSingleton(constant value) | MatchSequence(pattern* patterns) | MatchMapping(expr* keys, pattern* patterns, identifier? rest) | MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns) | MatchStar(identifier? name) -- The optional "rest" MatchMapping parameter handles capturing extra mapping keys | MatchAs(pattern? pattern, identifier? name) | MatchOr(pattern* patterns) 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 `_. 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 `_ directly. gast-0.6.0/SECURITY.rst000066400000000000000000000004031463734575300144720ustar00rootroot00000000000000Reporting 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 `_ directly. gast-0.6.0/gast/000077500000000000000000000000001463734575300134325ustar00rootroot00000000000000gast-0.6.0/gast/__init__.py000066400000000000000000000001571463734575300155460ustar00rootroot00000000000000from .gast import * from .version import __version__ from ast import NodeVisitor, NodeTransformer, iter_fields gast-0.6.0/gast/ast2.py000066400000000000000000000322061463734575300146600ustar00rootroot00000000000000from astn import AstToGAst, GAstToAst import ast import gast class Ast2ToGAst(AstToGAst): # mod def visit_Module(self, node): new_node = gast.Module( self._visit(node.body), [] # type_ignores ) return new_node # stmt 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), None, # returns None, # type_comment [], # type_params ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_ClassDef(self, node): new_node = gast.ClassDef( self._visit(node.name), self._visit(node.bases), [], # keywords self._visit(node.body), self._visit(node.decorator_list), [], # type_params ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Assign(self, node): new_node = gast.Assign( self._visit(node.targets), self._visit(node.value), None, # type_comment ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_For(self, node): new_node = gast.For( self._visit(node.target), self._visit(node.iter), self._visit(node.body), self._visit(node.orelse), [] # type_comment ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_With(self, node): new_node = gast.With( [gast.withitem( self._visit(node.context_expr), self._visit(node.optional_vars) )], self._visit(node.body), None, # type_comment ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Raise(self, node): ntype = self._visit(node.type) ninst = self._visit(node.inst) ntback = self._visit(node.tback) what = ntype if ninst is not None: what = gast.Call(ntype, [ninst], []) gast.copy_location(what, node) what.end_lineno = what.end_col_offset = None if ntback is not None: attr = gast.Attribute(what, 'with_traceback', gast.Load()) gast.copy_location(attr, node) attr.end_lineno = attr.end_col_offset = None what = gast.Call( attr, [ntback], [] ) gast.copy_location(what, node) what.end_lineno = what.end_col_offset = None new_node = gast.Raise(what, None) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_TryExcept(self, node): new_node = gast.Try( self._visit(node.body), self._visit(node.handlers), self._visit(node.orelse), [] # finalbody ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_TryFinally(self, node): new_node = gast.Try( self._visit(node.body), [], # handlers [], # orelse self._visit(node.finalbody) ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node # expr def visit_Name(self, node): new_node = gast.Name( self._visit(node.id), self._visit(node.ctx), None, None, ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Num(self, node): new_node = gast.Constant( node.n, None, ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Subscript(self, node): new_slice = self._visit(node.slice) new_node = gast.Subscript( self._visit(node.value), new_slice, self._visit(node.ctx), ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Ellipsis(self, node): new_node = gast.Constant( Ellipsis, None, ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Index(self, node): return self._visit(node.value) def visit_ExtSlice(self, node): new_dims = self._visit(node.dims) new_node = gast.Tuple(new_dims, gast.Load()) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Str(self, node): new_node = gast.Constant( node.s, None, ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Call(self, node): if node.starargs: star = gast.Starred(self._visit(node.starargs), gast.Load()) gast.copy_location(star, node) star.end_lineno = star.end_col_offset = None starred = [star] else: starred = [] if node.kwargs: kwargs = [gast.keyword(None, self._visit(node.kwargs))] else: kwargs = [] new_node = gast.Call( self._visit(node.func), self._visit(node.args) + starred, self._visit(node.keywords) + kwargs, ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_comprehension(self, node): new_node = gast.comprehension( target=self._visit(node.target), iter=self._visit(node.iter), ifs=self._visit(node.ifs), is_async=0, ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node # arguments def visit_arguments(self, node): # missing locations for vararg and kwarg set at function level if node.vararg: vararg = ast.Name(node.vararg, ast.Param()) else: vararg = None if node.kwarg: kwarg = ast.Name(node.kwarg, ast.Param()) else: kwarg = None if node.vararg: vararg = ast.Name(node.vararg, ast.Param()) else: vararg = None new_node = gast.arguments( self._visit(node.args), [], # posonlyargs self._visit(vararg), [], # kwonlyargs [], # kw_defaults self._visit(kwarg), self._visit(node.defaults), ) return new_node def visit_alias(self, node): new_node = gast.alias( self._visit(node.name), self._visit(node.asname), ) new_node.lineno = new_node.col_offset = None new_node.end_lineno = new_node.end_col_offset = None return new_node class GAstToAst2(GAstToAst): # mod def visit_Module(self, node): new_node = ast.Module(self._visit(node.body)) return new_node # stmt 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), ) # because node.args doesn't have any location to copy from if node.args.vararg: ast.copy_location(node.args.vararg, node) if node.args.kwarg: ast.copy_location(node.args.kwarg, node) ast.copy_location(new_node, node) return new_node def visit_ClassDef(self, node): new_node = ast.ClassDef( self._visit(node.name), self._visit(node.bases), self._visit(node.body), self._visit(node.decorator_list), ) ast.copy_location(new_node, node) return new_node def visit_Assign(self, node): new_node = ast.Assign( self._visit(node.targets), self._visit(node.value), ) ast.copy_location(new_node, node) return new_node def visit_For(self, node): new_node = ast.For( self._visit(node.target), self._visit(node.iter), self._visit(node.body), self._visit(node.orelse), ) ast.copy_location(new_node, node) return new_node def visit_With(self, node): new_node = ast.With( self._visit(node.items[0].context_expr), self._visit(node.items[0].optional_vars), self._visit(node.body) ) ast.copy_location(new_node, node) return new_node def visit_Raise(self, node): if isinstance(node.exc, gast.Call) and \ isinstance(node.exc.func, gast.Attribute) and \ node.exc.func.attr == 'with_traceback': raised = self._visit(node.exc.func.value) traceback = self._visit(node.exc.args[0]) else: raised = self._visit(node.exc) traceback = None new_node = ast.Raise(raised, None, traceback) ast.copy_location(new_node, node) return new_node def visit_Try(self, node): if node.finalbody: new_node = ast.TryFinally( self._visit(node.body), self._visit(node.finalbody) ) else: new_node = ast.TryExcept( self._visit(node.body), self._visit(node.handlers), self._visit(node.orelse), ) ast.copy_location(new_node, node) return new_node # expr def visit_Name(self, node): new_node = ast.Name( self._visit(node.id), self._visit(node.ctx), ) ast.copy_location(new_node, node) return new_node def visit_Constant(self, node): if isinstance(node.value, (bool, int, long, float, complex)): new_node = ast.Num(node.value) elif node.value is Ellipsis: new_node = ast.Ellipsis() else: new_node = ast.Str(node.value) ast.copy_location(new_node, node) return new_node def visit_Subscript(self, node): def adjust_slice(s): if isinstance(s, (ast.Slice, ast.Ellipsis)): return s else: return ast.Index(s) if isinstance(node.slice, gast.Tuple): new_slice = ast.ExtSlice([adjust_slice(self._visit(elt)) for elt in node.slice.elts]) else: new_slice = adjust_slice(self._visit(node.slice)) ast.copy_location(new_slice, node.slice) new_node = ast.Subscript( self._visit(node.value), new_slice, self._visit(node.ctx), ) ast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Call(self, node): if node.args and isinstance(node.args[-1], gast.Starred): args = node.args[:-1] starargs = node.args[-1].value else: args = node.args starargs = None if node.keywords and node.keywords[-1].arg is None: keywords = node.keywords[:-1] kwargs = node.keywords[-1].value else: keywords = node.keywords kwargs = None new_node = ast.Call( self._visit(node.func), self._visit(args), self._visit(keywords), self._visit(starargs), self._visit(kwargs), ) ast.copy_location(new_node, node) return new_node def visit_arg(self, node): new_node = ast.Name(node.arg, ast.Param()) ast.copy_location(new_node, node) return new_node # arguments def visit_arguments(self, node): vararg = node.vararg and node.vararg.id kwarg = node.kwarg and node.kwarg.id new_node = ast.arguments( self._visit(node.args), self._visit(vararg), self._visit(kwarg), self._visit(node.defaults), ) return new_node def visit_alias(self, node): new_node = ast.alias( self._visit(node.name), self._visit(node.asname) ) return new_node def ast_to_gast(node): return Ast2ToGAst().visit(node) def gast_to_ast(node): return GAstToAst2().visit(node) gast-0.6.0/gast/ast3.py000066400000000000000000000415731463734575300146700ustar00rootroot00000000000000from gast.astn import AstToGAst, GAstToAst import gast import ast import sys class Ast3ToGAst(AstToGAst): if sys.version_info.minor < 10: def visit_alias(self, node): new_node = gast.alias( self._visit(node.name), self._visit(node.asname), ) new_node.lineno = new_node.col_offset = None new_node.end_lineno = new_node.end_col_offset = None return new_node if sys.version_info.minor < 9: def visit_ExtSlice(self, node): new_node = gast.Tuple(self._visit(node.dims), gast.Load()) return gast.copy_location(new_node, node) def visit_Index(self, node): return self._visit(node.value) def visit_Assign(self, node): new_node = gast.Assign( self._visit(node.targets), self._visit(node.value), None, # type_comment ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node if sys.version_info.minor < 8: def visit_Module(self, node): new_node = gast.Module( self._visit(node.body), [] # type_ignores ) return new_node def visit_Num(self, node): new_node = gast.Constant( node.n, None, ) return gast.copy_location(new_node, node) def visit_Ellipsis(self, node): new_node = gast.Constant( Ellipsis, None, ) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node def visit_Str(self, node): new_node = gast.Constant( node.s, None, ) return gast.copy_location(new_node, node) def visit_Bytes(self, node): new_node = gast.Constant( node.s, None, ) return gast.copy_location(new_node, node) 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), None, # 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), None, # type_comment [], # type_params ) return gast.copy_location(new_node, node) def visit_For(self, node): new_node = gast.For( self._visit(node.target), self._visit(node.iter), self._visit(node.body), self._visit(node.orelse), None, # type_comment ) return gast.copy_location(new_node, node) def visit_AsyncFor(self, node): new_node = gast.AsyncFor( self._visit(node.target), self._visit(node.iter), self._visit(node.body), self._visit(node.orelse), None, # type_comment ) return gast.copy_location(new_node, node) def visit_With(self, node): new_node = gast.With( self._visit(node.items), self._visit(node.body), None, # type_comment ) return gast.copy_location(new_node, node) def visit_AsyncWith(self, node): new_node = gast.AsyncWith( self._visit(node.items), self._visit(node.body), None, # type_comment ) return gast.copy_location(new_node, node) def visit_Call(self, node): if sys.version_info.minor < 5: if node.starargs: star = gast.Starred(self._visit(node.starargs), gast.Load()) gast.copy_location(star, node) starred = [star] else: starred = [] if node.kwargs: kw = gast.keyword(None, self._visit(node.kwargs)) gast.copy_location(kw, node.kwargs) kwargs = [kw] else: kwargs = [] else: starred = kwargs = [] new_node = gast.Call( self._visit(node.func), self._visit(node.args) + starred, self._visit(node.keywords) + kwargs, ) return gast.copy_location(new_node, node) def visit_NameConstant(self, node): if node.value is None: new_node = gast.Constant(None, None) elif node.value is True: new_node = gast.Constant(True, None) elif node.value is False: new_node = gast.Constant(False, None) return gast.copy_location(new_node, node) def visit_arguments(self, node): new_node = gast.arguments( self._visit(node.args), [], # posonlyargs self._visit(node.vararg), self._visit(node.kwonlyargs), self._visit(node.kw_defaults), self._visit(node.kwarg), self._visit(node.defaults), ) return gast.copy_location(new_node, node) def visit_Name(self, node): new_node = gast.Name( node.id, # micro-optimization here, don't call self._visit self._visit(node.ctx), None, None, ) return ast.copy_location(new_node, node) def visit_arg(self, node): if sys.version_info.minor < 8: extra_arg = None else: extra_arg = self._visit(node.type_comment) new_node = gast.Name( node.arg, # micro-optimization here, don't call self._visit gast.Param(), self._visit(node.annotation), extra_arg # type_comment ) return ast.copy_location(new_node, node) def visit_ExceptHandler(self, node): if node.name: new_node = gast.ExceptHandler( self._visit(node.type), gast.Name(node.name, gast.Store(), None, None), self._visit(node.body)) return ast.copy_location(new_node, node) else: return self.generic_visit(node) if sys.version_info.minor < 6: def visit_comprehension(self, node): new_node = gast.comprehension( target=self._visit(node.target), iter=self._visit(node.iter), ifs=self._visit(node.ifs), is_async=0, ) 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: def visit_alias(self, node): new_node = ast.alias( self._visit(node.name), self._visit(node.asname) ) return new_node if sys.version_info.minor < 9: def visit_Subscript(self, node): def adjust_slice(s): if isinstance(s, ast.Slice): return s else: return ast.Index(s) if isinstance(node.slice, gast.Tuple): if any(isinstance(elt, gast.slice) for elt in node.slice.elts): new_slice = ast.ExtSlice( [adjust_slice(x) for x in self._visit(node.slice.elts)]) else: value = ast.Tuple(self._visit(node.slice.elts), ast.Load()) ast.copy_location(value, node.slice) new_slice = ast.Index(value) else: new_slice = adjust_slice(self._visit(node.slice)) ast.copy_location(new_slice, node.slice) new_node = ast.Subscript( self._visit(node.value), new_slice, self._visit(node.ctx), ) return ast.copy_location(new_node, node) def visit_Assign(self, node): new_node = ast.Assign( self._visit(node.targets), self._visit(node.value), ) return ast.copy_location(new_node, node) if sys.version_info.minor < 8: def visit_Module(self, node): new_node = ast.Module(self._visit(node.body)) return new_node def visit_Constant(self, node): if node.value is None: new_node = ast.NameConstant(node.value) elif node.value is Ellipsis: new_node = ast.Ellipsis() elif isinstance(node.value, bool): new_node = ast.NameConstant(node.value) elif isinstance(node.value, (int, float, complex)): new_node = ast.Num(node.value) elif isinstance(node.value, str): new_node = ast.Str(node.value) else: new_node = ast.Bytes(node.value) return ast.copy_location(new_node, node) def _make_arg(self, node): if node is None: return None if sys.version_info.minor < 8: extra_args = tuple() else: extra_args = self._visit(node.type_comment), new_node = ast.arg( self._visit(node.id), self._visit(node.annotation), *extra_args ) return ast.copy_location(new_node, node) def visit_Name(self, node): new_node = ast.Name( self._visit(node.id), self._visit(node.ctx), ) return ast.copy_location(new_node, node) def visit_ExceptHandler(self, node): if node.name: new_node = ast.ExceptHandler( self._visit(node.type), node.name.id, self._visit(node.body)) return ast.copy_location(new_node, node) else: return self.generic_visit(node) if sys.version_info.minor < 5: def visit_Call(self, node): if node.args and isinstance(node.args[-1], gast.Starred): args = node.args[:-1] starargs = node.args[-1].value else: args = node.args starargs = None if node.keywords and node.keywords[-1].arg is None: keywords = node.keywords[:-1] kwargs = node.keywords[-1].value else: keywords = node.keywords kwargs = None new_node = ast.Call( self._visit(node.func), self._visit(args), self._visit(keywords), self._visit(starargs), self._visit(kwargs), ) return ast.copy_location(new_node, node) def visit_ClassDef(self, node): self.generic_visit(node) new_node = ast.ClassDef( name=self._visit(node.name), bases=self._visit(node.bases), keywords=self._visit(node.keywords), body=self._visit(node.body), decorator_list=self._visit(node.decorator_list), starargs=None, kwargs=None, ) return ast.copy_location(new_node, node) elif sys.version_info.minor < 8: 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), ) 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), ) return ast.copy_location(new_node, node) def visit_For(self, node): new_node = ast.For( self._visit(node.target), self._visit(node.iter), self._visit(node.body), self._visit(node.orelse), ) return ast.copy_location(new_node, node) def visit_AsyncFor(self, node): new_node = ast.AsyncFor( self._visit(node.target), self._visit(node.iter), self._visit(node.body), self._visit(node.orelse), None, # type_comment ) return ast.copy_location(new_node, node) def visit_With(self, node): new_node = ast.With( self._visit(node.items), self._visit(node.body), ) return ast.copy_location(new_node, node) def visit_AsyncWith(self, node): new_node = ast.AsyncWith( self._visit(node.items), self._visit(node.body), ) return ast.copy_location(new_node, node) def visit_Call(self, node): new_node = ast.Call( self._visit(node.func), self._visit(node.args), 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), [self._make_arg(n) for n in node.kwonlyargs], self._visit(node.kw_defaults), self._make_arg(node.kwarg), self._visit(node.defaults), ] if sys.version_info.minor >= 8: new_node = ast.arguments( [self._make_arg(arg) for arg in node.posonlyargs], [self._make_arg(n) for n in node.args], *extra_args ) else: new_node = ast.arguments( [self._make_arg(n) for n in node.args], *extra_args ) return new_node def ast_to_gast(node): return Ast3ToGAst().visit(node) def gast_to_ast(node): return GAstToAst3().visit(node) gast-0.6.0/gast/astn.py000066400000000000000000000020411463734575300147460ustar00rootroot00000000000000import ast import gast def _generate_translators(to): class Translator(ast.NodeTransformer): def _visit(self, node): if isinstance(node, ast.AST): return self.visit(node) elif isinstance(node, list): return [self._visit(n) for n in node] else: return node def generic_visit(self, node): cls = type(node).__name__ try: new_node = getattr(to, cls)() except AttributeError: # handle nodes that are not part of the AST return for field in node._fields: setattr(new_node, field, self._visit(getattr(node, field))) for attr in node._attributes: try: setattr(new_node, attr, getattr(node, attr)) except AttributeError: pass return new_node return Translator AstToGAst = _generate_translators(gast) GAstToAst = _generate_translators(ast) gast-0.6.0/gast/gast.py000066400000000000000000000537011463734575300147500ustar00rootroot00000000000000import sys as _sys import ast as _ast from ast import boolop, cmpop, excepthandler, expr, expr_context, operator from ast import slice, stmt, unaryop, mod, AST from ast import iter_child_nodes, walk try: from ast import TypeIgnore except ImportError: class TypeIgnore(AST): pass try: from ast import pattern except ImportError: class pattern(AST): pass try: from ast import type_param except ImportError: class type_param(AST): pass def _make_node(Name, Fields, Attributes, Bases): # 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 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, type(Name, Bases, {'__init__': create_node, '_fields': Fields, '_attributes': Attributes})) _nodes = ( # mod ('Module', (('body', 'type_ignores'), (), (mod,))), ('Interactive', (('body',), (), (mod,))), ('Expression', (('body',), (), (mod,))), ('FunctionType', (('argtypes', 'returns'), (), (mod,))), ('Suite', (('body',), (), (mod,))), # stmt ('FunctionDef', (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('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', 'type_params',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Return', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Delete', (('targets',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('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,))), ('AnnAssign', (('target', 'annotation', 'value', 'simple',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Print', (('dest', 'values', 'nl',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('For', (('target', 'iter', 'body', 'orelse', 'type_comment'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('AsyncFor', (('target', 'iter', 'body', 'orelse', 'type_comment'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('While', (('test', 'body', 'orelse',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('If', (('test', 'body', 'orelse',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('With', (('items', 'body', 'type_comment'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('AsyncWith', (('items', 'body', 'type_comment'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Match', (('subject', 'cases'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Raise', (('exc', 'cause',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Try', (('body', 'handlers', 'orelse', 'finalbody',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('TryStar', (('body', 'handlers', 'orelse', 'finalbody',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Assert', (('test', 'msg',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Import', (('names',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('ImportFrom', (('module', 'names', 'level',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Exec', (('body', 'globals', 'locals',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Global', (('names',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Nonlocal', (('names',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Expr', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Pass', ((), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Break', ((), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), ('Continue', ((), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (stmt,))), # expr ('BoolOp', (('op', 'values',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('NamedExpr', (('target', 'value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('BinOp', (('left', 'op', 'right',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('UnaryOp', (('op', 'operand',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Lambda', (('args', 'body',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('IfExp', (('test', 'body', 'orelse',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Dict', (('keys', 'values',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Set', (('elts',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('ListComp', (('elt', 'generators',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('SetComp', (('elt', 'generators',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('DictComp', (('key', 'value', 'generators',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('GeneratorExp', (('elt', 'generators',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Await', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Yield', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('YieldFrom', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Compare', (('left', 'ops', 'comparators',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Call', (('func', 'args', 'keywords',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Repr', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('FormattedValue', (('value', 'conversion', 'format_spec',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('JoinedStr', (('values',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Constant', (('value', 'kind'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Attribute', (('value', 'attr', 'ctx',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Subscript', (('value', 'slice', 'ctx',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Starred', (('value', 'ctx',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Name', (('id', 'ctx', 'annotation', 'type_comment'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('List', (('elts', 'ctx',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), ('Tuple', (('elts', 'ctx',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (expr,))), # expr_context ('Load', ((), (), (expr_context,))), ('Store', ((), (), (expr_context,))), ('Del', ((), (), (expr_context,))), ('AugLoad', ((), (), (expr_context,))), ('AugStore', ((), (), (expr_context,))), ('Param', ((), (), (expr_context,))), # slice ('Slice', (('lower', 'upper', 'step'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset',), (slice,))), # boolop ('And', ((), (), (boolop,))), ('Or', ((), (), (boolop,))), # operator ('Add', ((), (), (operator,))), ('Sub', ((), (), (operator,))), ('Mult', ((), (), (operator,))), ('MatMult', ((), (), (operator,))), ('Div', ((), (), (operator,))), ('Mod', ((), (), (operator,))), ('Pow', ((), (), (operator,))), ('LShift', ((), (), (operator,))), ('RShift', ((), (), (operator,))), ('BitOr', ((), (), (operator,))), ('BitXor', ((), (), (operator,))), ('BitAnd', ((), (), (operator,))), ('FloorDiv', ((), (), (operator,))), # unaryop ('Invert', ((), (), (unaryop, AST,))), ('Not', ((), (), (unaryop, AST,))), ('UAdd', ((), (), (unaryop, AST,))), ('USub', ((), (), (unaryop, AST,))), # cmpop ('Eq', ((), (), (cmpop,))), ('NotEq', ((), (), (cmpop,))), ('Lt', ((), (), (cmpop,))), ('LtE', ((), (), (cmpop,))), ('Gt', ((), (), (cmpop,))), ('GtE', ((), (), (cmpop,))), ('Is', ((), (), (cmpop,))), ('IsNot', ((), (), (cmpop,))), ('In', ((), (), (cmpop,))), ('NotIn', ((), (), (cmpop,))), # comprehension ('comprehension', (('target', 'iter', 'ifs', 'is_async'), (), (AST,))), # excepthandler ('ExceptHandler', (('type', 'name', 'body'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (excepthandler,))), # arguments ('arguments', (('args', 'posonlyargs', 'vararg', 'kwonlyargs', 'kw_defaults', 'kwarg', 'defaults'), (), (AST,))), # keyword ('keyword', (('arg', 'value'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (AST,))), # alias ('alias', (('name', 'asname'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (AST,))), # withitem ('withitem', (('context_expr', 'optional_vars'), (), (AST,))), # match_case ('match_case', (('pattern', 'guard', 'body'), (), (AST,))), # pattern ('MatchValue', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), ('MatchSingleton', (('value',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), ('MatchSequence', (('patterns',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), ('MatchMapping', (('keys', 'patterns', 'rest'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), ('MatchClass', (('cls', 'patterns', 'kwd_attrs', 'kwd_patterns'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), ('MatchStar', (('name',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), ('MatchAs', (('pattern', 'name'), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), ('MatchOr', (('patterns',), ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'), (pattern,))), # 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) if _sys.version_info.major == 2: from .ast2 import ast_to_gast, gast_to_ast if _sys.version_info.major == 3: from .ast3 import ast_to_gast, gast_to_ast def parse(*args, **kwargs): return ast_to_gast(_ast.parse(*args, **kwargs)) def unparse(gast_obj): from .unparser import unparse return unparse(gast_obj) def literal_eval(node_or_string): if isinstance(node_or_string, AST): node_or_string = gast_to_ast(node_or_string) return _ast.literal_eval(node_or_string) def get_docstring(node, clean=True): if not isinstance(node, (FunctionDef, ClassDef, Module)): raise TypeError("%r can't have docstrings" % node.__class__.__name__) if node.body and isinstance(node.body[0], Expr) and \ isinstance(node.body[0].value, Constant): if clean: import inspect holder = node.body[0].value return inspect.cleandoc(getattr(holder, holder._fields[0])) return node.body[0].value.s # the following are directly imported from python3.8's Lib/ast.py # def copy_location(new_node, old_node): """ Copy source location (`lineno`, `col_offset`, `end_lineno`, and `end_col_offset` attributes) from *old_node* to *new_node* if possible, and return *new_node*. """ for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset': if attr in old_node._attributes and attr in new_node._attributes \ and hasattr(old_node, attr): setattr(new_node, attr, getattr(old_node, attr)) return new_node def fix_missing_locations(node): """ When you compile a node tree with compile(), the compiler expects lineno and col_offset attributes for every node that supports them. This is rather tedious to fill in for generated nodes, so this helper adds these attributes recursively where not already set, by setting them to the values of the parent node. It works recursively starting at *node*. """ def _fix(node, lineno, col_offset, end_lineno, end_col_offset): if 'lineno' in node._attributes: if not hasattr(node, 'lineno'): node.lineno = lineno else: lineno = node.lineno if 'end_lineno' in node._attributes: if not hasattr(node, 'end_lineno'): node.end_lineno = end_lineno else: end_lineno = node.end_lineno if 'col_offset' in node._attributes: if not hasattr(node, 'col_offset'): node.col_offset = col_offset else: col_offset = node.col_offset if 'end_col_offset' in node._attributes: if not hasattr(node, 'end_col_offset'): node.end_col_offset = end_col_offset else: end_col_offset = node.end_col_offset for child in iter_child_nodes(node): _fix(child, lineno, col_offset, end_lineno, end_col_offset) _fix(node, 1, 0, 1, 0) return node def increment_lineno(node, n=1): """ Increment the line number and end line number of each node in the tree starting at *node* by *n*. This is useful to "move code" to a different location in a file. """ for child in walk(node): if 'lineno' in child._attributes: child.lineno = (getattr(child, 'lineno', 0) or 0) + n 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] gast-0.6.0/gast/unparser.py000066400000000000000000001153211463734575300156460ustar00rootroot00000000000000# Code copied from Lib/ast.py from cpython 3.10 and slightly adjusted for gast # # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 # -------------------------------------------- # # 1. This LICENSE AGREEMENT is between the Python Software Foundation # ("PSF"), and the Individual or Organization ("Licensee") accessing and # otherwise using this software ("Python") in source or binary form and # its associated documentation. # # 2. Subject to the terms and conditions of this License Agreement, PSF hereby # grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, # analyze, test, perform and/or display publicly, prepare derivative works, # distribute, and otherwise use Python alone or in any derivative version, # provided, however, that PSF's License Agreement and PSF's notice of copyright, # i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; # All Rights Reserved" are retained in Python alone or in any derivative version # prepared by Licensee. # # 3. In the event Licensee prepares a derivative work that is based on # or incorporates Python or any part thereof, and wants to make # the derivative work available to others as provided herein, then # Licensee hereby agrees to include in any such work a brief summary of # the changes made to Python. # # 4. PSF is making Python available to Licensee on an "AS IS" # basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR # IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND # DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS # FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT # INFRINGE ANY THIRD PARTY RIGHTS. # # 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON # FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS # A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, # OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. # # 6. This License Agreement will automatically terminate upon a material # breach of its terms and conditions. # # 7. Nothing in this License Agreement shall be deemed to create any # relationship of agency, partnership, or joint venture between PSF and # Licensee. This License Agreement does not grant permission to use PSF # trademarks or trade name in a trademark sense to endorse or promote # products or services of Licensee, or any third party. # # 8. By copying, installing or otherwise using Python, Licensee # agrees to be bound by the terms and conditions of this License # Agreement. import sys from . import * from contextlib import contextmanager from string import printable class nullcontext(object): def __init__(self, enter_result=None): self.enter_result = enter_result def __enter__(self): return self.enter_result def __exit__(self, *excinfo): pass # Large float and imaginary literals get turned into infinities in the AST. # We unparse those infinities to INFSTR. _INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1) class _Precedence(object): """Precedence table that originated from python grammar.""" TUPLE = 1 YIELD = 2 # 'yield', 'yield from' TEST = 3 # 'if'-'else', 'lambda' OR = 4 # 'or' AND = 5 # 'and' NOT = 6 # 'not' CMP = 7 # '<', '>', '==', '>=', '<=', '!=', # 'in', 'not in', 'is', 'is not' EXPR = 8 BOR = EXPR # '|' BXOR = 9 # '^' BAND = 10 # '&' SHIFT = 11 # '<<', '>>' ARITH = 12 # '+', '-' TERM = 13 # '*', '@', '/', '%', '//' FACTOR = 14 # unary '+', '-', '~' POWER = 15 # '**' AWAIT = 16 # 'await' ATOM = 17 _SINGLE_QUOTES = ("'", '"') _MULTI_QUOTES = ('"""', "'''") _ALL_QUOTES = _SINGLE_QUOTES + _MULTI_QUOTES class _Unparser(NodeVisitor): """Methods in this class recursively traverse an AST and output source code for the abstract syntax; original formatting is disregarded.""" def __init__(self, _avoid_backslashes=False): self._source = [] self._buffer = [] self._precedences = {} self._type_ignores = {} self._indent = 0 self._avoid_backslashes = _avoid_backslashes def interleave(self, inter, f, seq): """Call f on each item in seq, calling inter() in between.""" seq = iter(seq) try: f(next(seq)) except StopIteration: pass else: for x in seq: inter() f(x) def items_view(self, traverser, items): """Traverse and separate the given *items* with a comma and append it to the buffer. If *items* is a single item sequence, a trailing comma will be added.""" if len(items) == 1: traverser(items[0]) self.write(",") else: self.interleave(lambda: self.write(", "), traverser, items) def maybe_newline(self): """Adds a newline if it isn't the start of generated source""" if self._source: self.write("\n") def fill(self, text=""): """Indent a piece of text and append it, according to the current indentation level""" self.maybe_newline() self.write(" " * self._indent + text) def write(self, text): """Append a piece of text""" self._source.append(text) def buffer_writer(self, text): self._buffer.append(text) @property def buffer(self): value = "".join(self._buffer) self._buffer.clear() return value @contextmanager def block(self, extra = None): """A context manager for preparing the source for blocks. It adds the character':', increases the indentation on enter and decreases the indentation on exit. If *extra* is given, it will be directly appended after the colon character. """ self.write(":") if extra: self.write(extra) self._indent += 1 yield self._indent -= 1 @contextmanager def delimit(self, start, end): """A context manager for preparing the source for expressions. It adds *start* to the buffer and enters, after exit it adds *end*.""" self.write(start) yield self.write(end) def delimit_if(self, start, end, condition): if condition: return self.delimit(start, end) else: return nullcontext() def require_parens(self, precedence, node): """Shortcut to adding precedence related parens""" return self.delimit_if("(", ")", self.get_precedence(node) > precedence) def get_precedence(self, node): return self._precedences.get(node, _Precedence.TEST) def set_precedence(self, precedence, *nodes): for node in nodes: self._precedences[node] = precedence def get_raw_docstring(self, node): """If a docstring node is found in the body of the *node* parameter, return that docstring node, None otherwise. Logic mirrored from ``_PyAST_GetDocString``.""" if not isinstance( node, (AsyncFunctionDef, FunctionDef, ClassDef, Module) ) or len(node.body) < 1: return None node = node.body[0] if not isinstance(node, Expr): return None node = node.value if isinstance(node, Constant) and isinstance(node.value, str): return node def get_type_comment(self, node): comment = self._type_ignores.get(node.lineno) or node.type_comment if comment is not None: return " # type: {}".format(comment) def traverse(self, node): if isinstance(node, list): for item in node: self.traverse(item) else: super(_Unparser, self).visit(node) # Note: as visit() resets the output text, do NOT rely on # NodeVisitor.generic_visit to handle any nodes (as it calls back in to # the subclass visit() method, which resets self._source to an empty list) def visit(self, node): """Outputs a source code string that, if converted back to an ast (using ast.parse) will generate an AST equivalent to *node*""" self._source = [] self.traverse(node) return "".join(self._source) def _write_docstring_and_traverse_body(self, node): docstring = self.get_raw_docstring(node) if docstring: self._write_docstring(docstring) self.traverse(node.body[1:]) else: self.traverse(node.body) def visit_Module(self, node): self._type_ignores = { ignore.lineno: "ignore{}".format(ignore.tag) for ignore in node.type_ignores } self._write_docstring_and_traverse_body(node) self._type_ignores.clear() def visit_FunctionType(self, node): with self.delimit("(", ")"): self.interleave( lambda: self.write(", "), self.traverse, node.argtypes ) self.write(" -> ") self.traverse(node.returns) def visit_Expr(self, node): self.fill() self.set_precedence(_Precedence.YIELD, node.value) self.traverse(node.value) def visit_NamedExpr(self, node): with self.require_parens(_Precedence.TUPLE, node): self.set_precedence(_Precedence.ATOM, node.target, node.value) self.traverse(node.target) self.write(" := ") self.traverse(node.value) def visit_Import(self, node): self.fill("import ") self.interleave(lambda: self.write(", "), self.traverse, node.names) def visit_ImportFrom(self, node): self.fill("from ") self.write("." * node.level) if node.module: self.write(node.module) self.write(" import ") self.interleave(lambda: self.write(", "), self.traverse, node.names) def visit_Assign(self, node): self.fill() for target in node.targets: self.traverse(target) self.write(" = ") self.traverse(node.value) type_comment = self.get_type_comment(node) if type_comment: self.write(type_comment) def visit_AugAssign(self, node): self.fill() self.traverse(node.target) self.write(" " + self.binop[node.op.__class__.__name__] + "= ") self.traverse(node.value) def visit_AnnAssign(self, node): self.fill() with self.delimit_if("(", ")", not node.simple and isinstance(node.target, Name)): self.traverse(node.target) self.write(": ") self.traverse(node.annotation) if node.value: self.write(" = ") self.traverse(node.value) def visit_Return(self, node): self.fill("return") if node.value: self.write(" ") self.traverse(node.value) def visit_Pass(self, node): self.fill("pass") def visit_Break(self, node): self.fill("break") def visit_Continue(self, node): self.fill("continue") def visit_Delete(self, node): self.fill("del ") self.interleave(lambda: self.write(", "), self.traverse, node.targets) def visit_Assert(self, node): self.fill("assert ") self.traverse(node.test) if node.msg: self.write(", ") self.traverse(node.msg) def visit_Global(self, node): self.fill("global ") self.interleave(lambda: self.write(", "), self.write, node.names) def visit_Nonlocal(self, node): self.fill("nonlocal ") self.interleave(lambda: self.write(", "), self.write, node.names) def visit_Await(self, node): with self.require_parens(_Precedence.AWAIT, node): self.write("await") if node.value: self.write(" ") self.set_precedence(_Precedence.ATOM, node.value) self.traverse(node.value) def visit_Yield(self, node): with self.require_parens(_Precedence.YIELD, node): self.write("yield") if node.value: self.write(" ") self.set_precedence(_Precedence.ATOM, node.value) self.traverse(node.value) def visit_YieldFrom(self, node): with self.require_parens(_Precedence.YIELD, node): self.write("yield from ") if not node.value: raise ValueError("Node can't be used without a value attribute.") self.set_precedence(_Precedence.ATOM, node.value) self.traverse(node.value) def visit_Raise(self, node): self.fill("raise") if not node.exc: if node.cause: raise ValueError("Node can't use cause without an exception.") return self.write(" ") self.traverse(node.exc) if node.cause: self.write(" from ") self.traverse(node.cause) def visit_Try(self, node): self.fill("try") with self.block(): self.traverse(node.body) for ex in node.handlers: self.traverse(ex) if node.orelse: self.fill("else") with self.block(): self.traverse(node.orelse) if node.finalbody: self.fill("finally") with self.block(): self.traverse(node.finalbody) def visit_ExceptHandler(self, node): self.fill("except") if node.type: self.write(" ") self.traverse(node.type) if node.name: self.write(" as ") self.write(node.name.id) with self.block(): self.traverse(node.body) def visit_ClassDef(self, node): self.maybe_newline() for deco in node.decorator_list: 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: if comma: self.write(", ") else: comma = True self.traverse(e) for e in node.keywords: if comma: self.write(", ") else: comma = True self.traverse(e) with self.block(): self._write_docstring_and_traverse_body(node) def visit_FunctionDef(self, node): self._function_helper(node, "def") def visit_AsyncFunctionDef(self, node): self._function_helper(node, "async def") def _function_helper(self, node, fill_suffix): self.maybe_newline() for deco in node.decorator_list: self.fill("@") 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: self.write(" -> ") self.traverse(node.returns) 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) def visit_AsyncFor(self, node): self._for_helper("async for ", node) def _for_helper(self, fill, node): self.fill(fill) self.traverse(node.target) self.write(" in ") self.traverse(node.iter) with self.block(extra=self.get_type_comment(node)): self.traverse(node.body) if node.orelse: self.fill("else") with self.block(): self.traverse(node.orelse) def visit_If(self, node): self.fill("if ") self.traverse(node.test) with self.block(): self.traverse(node.body) # collapse nested ifs into equivalent elifs. while node.orelse and len(node.orelse) == 1 and isinstance(node.orelse[0], If): node = node.orelse[0] self.fill("elif ") self.traverse(node.test) with self.block(): self.traverse(node.body) # final else if node.orelse: self.fill("else") with self.block(): self.traverse(node.orelse) def visit_While(self, node): self.fill("while ") self.traverse(node.test) with self.block(): self.traverse(node.body) if node.orelse: self.fill("else") with self.block(): self.traverse(node.orelse) def visit_With(self, node): self.fill("with ") self.interleave(lambda: self.write(", "), self.traverse, node.items) with self.block(extra=self.get_type_comment(node)): self.traverse(node.body) def visit_AsyncWith(self, node): self.fill("async with ") self.interleave(lambda: self.write(", "), self.traverse, node.items) with self.block(extra=self.get_type_comment(node)): self.traverse(node.body) def _str_literal_helper( self, string, quote_types=_ALL_QUOTES, escape_special_whitespace=False ): """Helper for writing string literals, minimizing escapes. Returns the tuple (string literal to write, possible quote types). """ def escape_char(c): # \n and \t are non-printable, but we only escape them if # escape_special_whitespace is True if not escape_special_whitespace and c in "\n\t": return c # Always escape backslashes and other non-printable characters if c == "\\" or not all(cc in printable for cc in c): return c.encode("unicode_escape").decode("ascii") return c escaped_string = "".join(map(escape_char, string)) possible_quotes = quote_types if "\n" in escaped_string: possible_quotes = [q for q in possible_quotes if q in _MULTI_QUOTES] possible_quotes = [q for q in possible_quotes if q not in escaped_string] if not possible_quotes: # If there aren't any possible_quotes, fallback to using repr # on the original string. Try to use a quote from quote_types, # e.g., so that we use triple quotes for docstrings. string = repr(string) quote = next((q for q in quote_types if string[0] in q), string[0]) return string[1:-1], [quote] if escaped_string: # Sort so that we prefer '''"''' over """\"""" possible_quotes.sort(key=lambda q: q[0] == escaped_string[-1]) # If we're using triple quotes and we'd need to escape a final # quote, escape it if possible_quotes[0][0] == escaped_string[-1]: assert len(possible_quotes[0]) == 3 escaped_string = escaped_string[:-1] + "\\" + escaped_string[-1] return escaped_string, possible_quotes def _write_str_avoiding_backslashes(self, string, quote_types=_ALL_QUOTES): """Write string literal value with a best effort attempt to avoid backslashes.""" string, quote_types = self._str_literal_helper(string, quote_types=quote_types) quote_type = quote_types[0] self.write("{0}{1}{0}".format(quote_type, string)) def visit_JoinedStr(self, node): self.write("f") if self._avoid_backslashes: self._fstring_JoinedStr(node, self.buffer_writer) self._write_str_avoiding_backslashes(self.buffer) return # If we don't need to avoid backslashes globally (i.e., we only need # to avoid them inside FormattedValues), it's cosmetically preferred # to use escaped whitespace. That is, it's preferred to use backslashes # for cases like: f"{x}\n". To accomplish this, we keep track of what # in our buffer corresponds to FormattedValues and what corresponds to # Constant parts of the f-string, and allow escapes accordingly. buffer = [] for value in node.values: meth = getattr(self, "_fstring_" + type(value).__name__) meth(value, self.buffer_writer) buffer.append((self.buffer, isinstance(value, Constant))) new_buffer = [] quote_types = _ALL_QUOTES for value, is_constant in buffer: # Repeatedly narrow down the list of possible quote_types value, quote_types = self._str_literal_helper( value, quote_types=quote_types, escape_special_whitespace=is_constant ) new_buffer.append(value) value = "".join(new_buffer) quote_type = quote_types[0] self.write("{0}{1}{0}".format(quote_type, value)) def visit_FormattedValue(self, node): self.write("f") self._fstring_FormattedValue(node, self.buffer_writer) self._write_str_avoiding_backslashes(self.buffer) def _fstring_JoinedStr(self, node, write): for value in node.values: meth = getattr(self, "_fstring_" + type(value).__name__) meth(value, write) def _fstring_Constant(self, node, write): if not isinstance(node.value, str): raise ValueError("Constants inside JoinedStr should be a string.") value = node.value.replace("{", "{{").replace("}", "}}") write(value) def _fstring_FormattedValue(self, node, write): write("{") unparser = type(self)(_avoid_backslashes=True) unparser.set_precedence(_Precedence.TEST + 1, node.value) expr = unparser.visit(node.value) if expr.startswith("{"): write(" ") # Separate pair of opening brackets as "{ {" if "\\" in expr: raise ValueError("Unable to avoid backslash in f-string expression part") write(expr) if node.conversion != -1: conversion = chr(node.conversion) if conversion not in "sra": raise ValueError("Unknown f-string conversion.") write("!{}".format(conversion)) if node.format_spec: write(":") meth = getattr(self, "_fstring_" + type(node.format_spec).__name__) meth(node.format_spec, write) write("}") def visit_Name(self, node): self.write(node.id) def _write_docstring(self, node): self.fill() if node.kind == "u": self.write("u") self._write_str_avoiding_backslashes(node.value, quote_types=_MULTI_QUOTES) def _write_constant(self, value): if isinstance(value, (float, complex)): # Substitute overflowing decimal literal for AST infinities, # and inf - inf for NaNs. self.write( repr(value) .replace("inf", _INFSTR) .replace("nan", "({0}-{0})".format(_INFSTR)) ) elif self._avoid_backslashes and isinstance(value, str): self._write_str_avoiding_backslashes(value) else: self.write(repr(value)) def visit_Constant(self, node): value = node.value if isinstance(value, tuple): with self.delimit("(", ")"): self.items_view(self._write_constant, value) elif value is Ellipsis: self.write("...") else: if node.kind == "u": self.write("u") self._write_constant(node.value) def visit_List(self, node): with self.delimit("[", "]"): self.interleave(lambda: self.write(", "), self.traverse, node.elts) def visit_ListComp(self, node): with self.delimit("[", "]"): self.traverse(node.elt) for gen in node.generators: self.traverse(gen) def visit_GeneratorExp(self, node): with self.delimit("(", ")"): self.traverse(node.elt) for gen in node.generators: self.traverse(gen) def visit_SetComp(self, node): with self.delimit("{", "}"): self.traverse(node.elt) for gen in node.generators: self.traverse(gen) def visit_DictComp(self, node): with self.delimit("{", "}"): self.traverse(node.key) self.write(": ") self.traverse(node.value) for gen in node.generators: self.traverse(gen) def visit_comprehension(self, node): if node.is_async: self.write(" async for ") else: self.write(" for ") self.set_precedence(_Precedence.TUPLE, node.target) self.traverse(node.target) self.write(" in ") self.set_precedence(_Precedence.TEST + 1, node.iter, *node.ifs) self.traverse(node.iter) for if_clause in node.ifs: self.write(" if ") self.traverse(if_clause) def visit_IfExp(self, node): with self.require_parens(_Precedence.TEST, node): self.set_precedence(_Precedence.TEST + 1, node.body, node.test) self.traverse(node.body) self.write(" if ") self.traverse(node.test) self.write(" else ") self.set_precedence(_Precedence.TEST, node.orelse) self.traverse(node.orelse) def visit_Set(self, node): if node.elts: with self.delimit("{", "}"): self.interleave(lambda: self.write(", "), self.traverse, node.elts) else: # `{}` would be interpreted as a dictionary literal, and # `set` might be shadowed. Thus: self.write('{*()}') def visit_Dict(self, node): def write_key_value_pair(k, v): self.traverse(k) self.write(": ") self.traverse(v) def write_item(item): k, v = item if k is None: # for dictionary unpacking operator in dicts {**{'y': 2}} # see PEP 448 for details self.write("**") self.set_precedence(_Precedence.EXPR, v) self.traverse(v) else: write_key_value_pair(k, v) with self.delimit("{", "}"): self.interleave( lambda: self.write(", "), write_item, zip(node.keys, node.values) ) def visit_Tuple(self, node): with self.delimit("(", ")"): self.items_view(self.traverse, node.elts) unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"} unop_precedence = { "not": _Precedence.NOT, "~": _Precedence.FACTOR, "+": _Precedence.FACTOR, "-": _Precedence.FACTOR, } def visit_UnaryOp(self, node): operator = self.unop[node.op.__class__.__name__] operator_precedence = self.unop_precedence[operator] with self.require_parens(operator_precedence, node): self.write(operator) # factor prefixes (+, -, ~) shouldn't be seperated # from the value they belong, (e.g: +1 instead of + 1) if operator_precedence is not _Precedence.FACTOR: self.write(" ") self.set_precedence(operator_precedence, node.operand) self.traverse(node.operand) binop = { "Add": "+", "Sub": "-", "Mult": "*", "MatMult": "@", "Div": "/", "Mod": "%", "LShift": "<<", "RShift": ">>", "BitOr": "|", "BitXor": "^", "BitAnd": "&", "FloorDiv": "//", "Pow": "**", } binop_precedence = { "+": _Precedence.ARITH, "-": _Precedence.ARITH, "*": _Precedence.TERM, "@": _Precedence.TERM, "/": _Precedence.TERM, "%": _Precedence.TERM, "<<": _Precedence.SHIFT, ">>": _Precedence.SHIFT, "|": _Precedence.BOR, "^": _Precedence.BXOR, "&": _Precedence.BAND, "//": _Precedence.TERM, "**": _Precedence.POWER, } binop_rassoc = frozenset(("**",)) def visit_BinOp(self, node): operator = self.binop[node.op.__class__.__name__] operator_precedence = self.binop_precedence[operator] with self.require_parens(operator_precedence, node): if operator in self.binop_rassoc: left_precedence = operator_precedence + 1 right_precedence = operator_precedence else: left_precedence = operator_precedence right_precedence = operator_precedence + 1 self.set_precedence(left_precedence, node.left) self.traverse(node.left) self.write(" {} ".format(operator)) self.set_precedence(right_precedence, node.right) self.traverse(node.right) cmpops = { "Eq": "==", "NotEq": "!=", "Lt": "<", "LtE": "<=", "Gt": ">", "GtE": ">=", "Is": "is", "IsNot": "is not", "In": "in", "NotIn": "not in", } def visit_Compare(self, node): with self.require_parens(_Precedence.CMP, node): self.set_precedence(_Precedence.CMP + 1, node.left, *node.comparators) self.traverse(node.left) for o, e in zip(node.ops, node.comparators): self.write(" " + self.cmpops[o.__class__.__name__] + " ") self.traverse(e) boolops = {"And": "and", "Or": "or"} boolop_precedence = {"and": _Precedence.AND, "or": _Precedence.OR} def visit_BoolOp(self, node): operator = self.boolops[node.op.__class__.__name__] operator_precedence = [self.boolop_precedence[operator]] def increasing_level_traverse(node): operator_precedence[0] += 1 self.set_precedence(operator_precedence[0], node) self.traverse(node) with self.require_parens(operator_precedence[0], node): s = " {} ".format(operator) self.interleave(lambda: self.write(s), increasing_level_traverse, node.values) def visit_Attribute(self, node): self.set_precedence(_Precedence.ATOM, node.value) self.traverse(node.value) # Special case: 3.__abs__() is a syntax error, so if node.value # is an integer literal then we need to either parenthesize # it or add an extra space to get 3 .__abs__(). if isinstance(node.value, Constant) and isinstance(node.value.value, int): self.write(" ") self.write(".") self.write(node.attr) def visit_Call(self, node): self.set_precedence(_Precedence.ATOM, node.func) self.traverse(node.func) with self.delimit("(", ")"): comma = False for e in node.args: if comma: self.write(", ") else: comma = True self.traverse(e) for e in node.keywords: if comma: self.write(", ") else: comma = True self.traverse(e) def visit_Subscript(self, node): def is_simple_tuple(slice_value): # when unparsing a non-empty tuple, the parentheses can be safely # omitted if there aren't any elements that explicitly requires # parentheses (such as starred expressions). return ( isinstance(slice_value, Tuple) and slice_value.elts and not any(isinstance(elt, Starred) for elt in slice_value.elts) ) self.set_precedence(_Precedence.ATOM, node.value) self.traverse(node.value) with self.delimit("[", "]"): if is_simple_tuple(node.slice): self.items_view(self.traverse, node.slice.elts) else: self.traverse(node.slice) def visit_Starred(self, node): self.write("*") self.set_precedence(_Precedence.EXPR, node.value) self.traverse(node.value) def visit_Ellipsis(self, node): self.write("...") def visit_Slice(self, node): if node.lower: self.traverse(node.lower) self.write(":") if node.upper: self.traverse(node.upper) if node.step: self.write(":") self.traverse(node.step) def visit_Match(self, node): self.fill("match ") self.traverse(node.subject) with self.block(): for case in node.cases: self.traverse(case) def visit_arg(self, node): self.write(node.arg.id) if node.annotation: self.write(": ") self.traverse(node.annotation) def visit_arguments(self, node): first = True # normal arguments all_args = node.posonlyargs + node.args defaults = [None] * (len(all_args) - len(node.defaults)) + node.defaults for index, elements in enumerate(zip(all_args, defaults), 1): a, d = elements if first: first = False else: self.write(", ") self.traverse(a) if d: self.write("=") self.traverse(d) if index == len(node.posonlyargs): self.write(", /") # varargs, or bare '*' if no varargs but keyword-only arguments present if node.vararg or node.kwonlyargs: if first: first = False else: self.write(", ") self.write("*") if node.vararg: self.write(node.vararg.id) if node.vararg.annotation: self.write(": ") self.traverse(node.vararg.annotation) # keyword-only arguments if node.kwonlyargs: for a, d in zip(node.kwonlyargs, node.kw_defaults): self.write(", ") self.traverse(a) if d: self.write("=") self.traverse(d) # kwargs if node.kwarg: if first: first = False else: self.write(", ") self.write("**" + node.kwarg.id) if node.kwarg.annotation: self.write(": ") self.traverse(node.kwarg.annotation) def visit_keyword(self, node): if node.arg is None: self.write("**") else: self.write(node.arg) self.write("=") self.traverse(node.value) def visit_Lambda(self, node): with self.require_parens(_Precedence.TEST, node): self.write("lambda ") self.traverse(node.args) self.write(": ") self.set_precedence(_Precedence.TEST, node.body) self.traverse(node.body) def visit_alias(self, node): self.write(node.name) if node.asname: self.write(" as " + node.asname) def visit_withitem(self, node): self.traverse(node.context_expr) if node.optional_vars: self.write(" as ") self.traverse(node.optional_vars) def visit_match_case(self, node): self.fill("case ") self.traverse(node.pattern) if node.guard: self.write(" if ") self.traverse(node.guard) with self.block(): self.traverse(node.body) def visit_MatchValue(self, node): self.traverse(node.value) def visit_MatchSingleton(self, node): self._write_constant(node.value) def visit_MatchSequence(self, node): with self.delimit("[", "]"): self.interleave( lambda: self.write(", "), self.traverse, node.patterns ) def visit_MatchStar(self, node): name = node.name if name is None: name = "_" self.write("*{}".format(name)) def visit_MatchMapping(self, node): def write_key_pattern_pair(pair): k, p = pair self.traverse(k) self.write(": ") self.traverse(p) with self.delimit("{", "}"): keys = node.keys self.interleave( lambda: self.write(", "), write_key_pattern_pair, zip(keys, node.patterns, strict=True), ) rest = node.rest if rest is not None: if keys: self.write(", ") self.write("**{}".format(rest)) def visit_MatchClass(self, node): self.set_precedence(_Precedence.ATOM, node.cls) self.traverse(node.cls) with self.delimit("(", ")"): patterns = node.patterns self.interleave( lambda: self.write(", "), self.traverse, patterns ) attrs = node.kwd_attrs if attrs: def write_attr_pattern(pair): attr, pattern = pair self.write("{}=".format(attr)) self.traverse(pattern) if patterns: self.write(", ") self.interleave( lambda: self.write(", "), write_attr_pattern, zip(attrs, node.kwd_patterns, strict=True), ) def visit_MatchAs(self, node): name = node.name pattern = node.pattern if name is None: self.write("_") elif pattern is None: self.write(node.name) else: with self.require_parens(_Precedence.TEST, node): self.set_precedence(_Precedence.BOR, node.pattern) self.traverse(node.pattern) self.write(" as {}".format(node.name)) def visit_MatchOr(self, node): with self.require_parens(_Precedence.BOR, node): self.set_precedence(_Precedence.BOR + 1, *node.patterns) self.interleave(lambda: self.write(" | "), self.traverse, node.patterns) def unparse(ast_obj): unparser = _Unparser() return unparser.visit(ast_obj) gast-0.6.0/gast/version.py000066400000000000000000000000261463734575300154670ustar00rootroot00000000000000__version__ = '0.6.0' gast-0.6.0/setup.py000066400000000000000000000036041463734575300142110ustar00rootroot00000000000000# Use the newer `setuptools.setup()`, if available. try: from setuptools import setup kw = { 'test_suite': 'tests', } except ImportError: from distutils.core import setup kw = {} import os versionfile = os.path.join('gast', 'version.py') exec(open(versionfile).read()) setup(name='gast', # gast, daou naer! version=__version__, packages=['gast'], description='Python AST that abstracts the underlying Python version', long_description=''' A generic AST to represent Python2 and Python3's Abstract Syntax Tree(AST). GAST provides a compatibility layer between the AST of various Python versions, as produced by ``ast.parse`` from the standard ``ast`` module.''', author='serge-sans-paille', author_email='serge.guelton@telecom-bretagne.eu', url='https://github.com/serge-sans-paille/gast/', license="BSD 3-Clause", classifiers=['Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Natural Language :: English', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', ], python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', **kw ) gast-0.6.0/tests/000077500000000000000000000000001463734575300136365ustar00rootroot00000000000000gast-0.6.0/tests/__init__.py000066400000000000000000000000561463734575300157500ustar00rootroot00000000000000"""Package containing unit tests for gast.""" gast-0.6.0/tests/test_api.py000066400000000000000000000110521463734575300160170ustar00rootroot00000000000000import unittest import ast import gast import sys def dump(node): return gast.dump(node, show_empty=True) class APITestCase(unittest.TestCase): def test_literal_eval_string(self): code = "1, 3" self.assertEqual(ast.literal_eval(code), gast.literal_eval(code)) def test_literal_eval_code(self): code = "[1, 3]" tree = ast.parse(code, mode='eval') gtree = gast.parse(code, mode='eval') self.assertEqual(ast.literal_eval(tree), gast.literal_eval(gtree)) def test_parse(self): code = ''' def foo(x=1, *args, **kwargs): return x + y +len(args) + len(kwargs) ''' gast.parse(code) def test_unparse(self): code = 'def foo(x=1): return x' self.assertEqual(gast.unparse(gast.parse(code)), 'def foo(x=1):\n return x') def test_dump(self): code = 'lambda x: x' tree = gast.parse(code, mode='eval') zdump = dump(tree) norm = ("Expression(body=Lambda(args=arguments(args=[Name(" "id='x', ctx=Param(), " "annotation=None, type_comment=None)], posonlyargs=[], " "vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, " "defaults=[]), body=Name(id='x', ctx=Load(), " "annotation=None, type_comment=None)" "))") self.assertEqual(zdump, norm) def test_walk(self): code = 'x + 1' tree = gast.parse(code, mode='eval') 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(zdump, norm) self.assertEqual(len(list(gast.walk(tree))), 6) def test_iter_fields(self): tree = gast.Constant(value=1, kind=None) self.assertEqual({name for name, _ in gast.iter_fields(tree)}, {'value', 'kind'}) def test_iter_child_nodes(self): tree = gast.UnaryOp(gast.USub(), gast.Constant(value=1, kind=None)) self.assertEqual(len(list(gast.iter_fields(tree))), 2) def test_increment_lineno(self): tree = gast.Constant(value=1, kind=None) tree.lineno = 1 gast.increment_lineno(tree) self.assertEqual(tree.lineno, 2) def test_get_docstring(self): code = 'def foo(): "foo"' tree = gast.parse(code) func = tree.body[0] docs = gast.get_docstring(func) self.assertEqual(docs, "foo") def test_copy_location(self): tree = gast.Constant(value=1, kind=None) tree.lineno = 1 tree.col_offset = 2 node = gast.Constant(value=2, kind=None) gast.copy_location(node, tree) self.assertEqual(node.lineno, tree.lineno) self.assertEqual(node.col_offset, tree.col_offset) def test_fix_missing_locations(self): node = gast.Constant(value=6, kind=None) tree = gast.UnaryOp(gast.USub(), node) tree.lineno = 1 tree.col_offset = 2 gast.fix_missing_locations(tree) self.assertEqual(node.lineno, tree.lineno) self.assertEqual(node.col_offset, tree.col_offset) def test_NodeTransformer(self): node = gast.Constant(value=6, kind=None) tree = gast.UnaryOp(gast.USub(), node) class Trans(gast.NodeTransformer): def visit_Constant(self, node): node.value *= 2 return node tree = Trans().visit(tree) self.assertEqual(node.value, 12) def test_NodeVisitor(self): node = gast.Constant(value=6, kind=None) tree = gast.UnaryOp(gast.USub(), node) class Vis(gast.NodeTransformer): def __init__(self): self.state = [] def visit_Constant(self, node): self.state.append(node.value) vis = Vis() vis.visit(tree) self.assertEqual(vis.state, [6]) def test_NodeConstructor(self): node0 = gast.Name() load = gast.Load() node1 = gast.Name('id', load, None, None) node2 = gast.Name('id', load, None, type_comment=None) with self.assertRaises(TypeError): node1 = gast.Name('id', 'ctx', 'annotation', 'type_comment', 'random_field') for field in gast.Name._fields: self.assertEqual(getattr(node1, field), getattr(node2, field)) if __name__ == '__main__': unittest.main() gast-0.6.0/tests/test_compat.py000066400000000000000000000574051463734575300165450ustar00rootroot00000000000000import unittest import gast 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): code = 'def foo((x, y)): return x, y' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=" "[Tuple(elts=[Name(id='x', ctx=Store(), annotation=None, " "type_comment=None), Name(id='y', ctx=Store(), " "annotation=None, type_comment=None)], ctx=Store())], " "posonlyargs=[], vararg=None, " "kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), " "body=[Return(value=Tuple(elts=[Name(id='x', ctx=Load(), " "annotation=None, type_comment=None), " "Name(id='y', ctx=Load(), " "annotation=None, type_comment=None" ")], ctx=Load()))], decorator_list=" "[], returns=None, type_comment=None, type_params=[])], " "type_ignores=[])") self.assertEqual(dump(tree), norm) else: def test_ArgAnnotation(self): code = 'def foo(x:int): pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=" "[Name(id='x', ctx=Param(), annotation=Name" "(id='int', ctx=Load(), annotation=None, type_comment=None" "), type_comment=None)], posonlyargs=" "[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=" "None, defaults=[]), body=[Pass()], decorator_list=[], " "returns=None, type_comment=None, type_params=[])], " "type_ignores=[])") self.assertEqual(dump(tree), norm) def test_KeywordOnlyArgument(self): code = 'def foo(*, x=1): pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=" "[], posonlyargs=[], vararg=None, kwonlyargs=[Name" "(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_params=[])], " "type_ignores=[])") self.assertEqual(dump(tree), norm) if sys.version_info.minor >= 6: def test_FormattedValue(self): code = 'e = 1; f"{e}"' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Assign(targets=[Name(id='e', ctx=Store()" ", annotation=None, type_comment=None" ")], value=Constant(value=1, kind=None), " "type_comment=None), Expr(value=" "JoinedStr(values=[FormattedValue(value=Name(id='e', " "ctx=Load(), annotation=None, type_comment=None), " "conversion=-1, format_spec=None)]))], " "type_ignores=[])") self.assertEqual(dump(tree), norm) def test_JoinedStr(self): code = 'e = 1; f"e = {e}"' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Assign(targets=[Name(id='e', ctx=Store()" ", annotation=None, type_comment=None" ")], value=Constant(value=1, kind=None), " "type_comment=None), Expr(value=" "JoinedStr(values=[Constant(value='e = ', kind=None), " "FormattedValue(value=Name(id='e', ctx=Load(), " "annotation=None, type_comment=None), " "conversion=-1, format_spec=None)]))], " "type_ignores=[])") self.assertEqual(dump(tree), norm) if sys.version_info.minor >= 8: def test_TypeIgnore(self): code = 'def foo(): pass # type: ignore[excuse]' tree = gast.parse(code, type_comments=True) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(" "args=[], posonlyargs=[], vararg=None, kwonlyargs=[], " "kw_defaults=[], kwarg=None, defaults=[]), body=[" "Pass()], decorator_list=[], returns=None, " "type_comment=None, type_params=[])], type_ignores=" "[TypeIgnore(lineno=1, tag='[excuse]')])") self.assertEqual(dump(tree), norm) def test_PosonlyArgs(self): code = 'def foo(a, /, b): pass' tree = gast.parse(code, type_comments=True) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(" "args=[Name(id='b', ctx=Param(), annotation=None, " "type_comment=None)], posonlyargs=[Name(id='a', " "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_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_NamedExpr(self): code = '(x := 1) ' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Expr(value=NamedExpr(target=Name(id='x'," " ctx=Store(), annotation=None, type_comment=None), " "value=Constant(value=1, kind=None)))], type_ignores=" "[])") self.assertEqual(dump(tree), norm) if sys.version_info.minor >= 10: def test_MatchValue(self): code = 'match v:\n case "hello":...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=" "[match_case(pattern=MatchValue(value=Constant(" "value='hello', kind=None)), guard=None, body=" "[Expr(value=Constant(value=Ellipsis, kind=None))]" ")])], type_ignores=[])" ) self.assertEqual(dump(tree), norm) def test_MatchSingleton(self): code = 'match v:\n case None:...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=[" "match_case(pattern=MatchSingleton(value=None), " "guard=None, body=[Expr(value=Constant(value=" "Ellipsis, kind=None))])])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_MatchSequence(self): code = 'match v:\n case a, b:...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=" "[match_case(pattern=MatchSequence(patterns=[" "MatchAs(pattern=None, name='a'), MatchAs(pattern" "=None, name='b')]), guard=None, body=[Expr(value" "=Constant(value=Ellipsis, kind=None))])])], " "type_ignores=[])") self.assertEqual(dump(tree), norm) def test_MatchMapping(self): code = 'match v:\n case {1: a}:...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=[" "match_case(pattern=MatchMapping(keys=[Constant(" "value=1, kind=None)], patterns=[MatchAs(pattern" "=None, name='a')], rest=None), guard=None, body=" "[Expr(value=Constant(value=Ellipsis, kind=None))]" ")])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_MatchClass(self): code = 'match v:\n case Cls(attr=1):...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=[" "match_case(pattern=MatchClass(cls=Name(id='Cls'" ", ctx=Load(), annotation=None, type_comment=None" "), patterns=[], kwd_attrs=['attr'], kwd_patterns" "=[MatchValue(value=Constant(value=1, kind=None))" "]), guard=None, body=[Expr(value=Constant(value=" "Ellipsis, kind=None))])])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_MatchStar(self): code = 'match v:\n case [1, *other]:...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=[" "match_case(pattern=MatchSequence(patterns=[" "MatchValue(value=Constant(value=1, kind=None)), " "MatchStar(name='other')]), guard=None, body=" "[Expr(value=Constant(value=Ellipsis, kind=None)" ")])])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_MatchAs(self): code = 'match v:\n case 1, other:...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=[" "match_case(pattern=MatchSequence(patterns=[" "MatchValue(value=Constant(value=1, kind=None)), " "MatchAs(pattern=None, name='other')]), guard=None" ", body=[Expr(value=Constant(value=Ellipsis, kind" "=None))])])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_MatchOr(self): code = 'match v:\n case 1 | 2:...' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Match(subject=Name(id='v', ctx=Load" "(), annotation=None, type_comment=None), cases=[" "match_case(pattern=MatchOr(patterns=[MatchValue(" "value=Constant(value=1, kind=None)), MatchValue(" "value=Constant(value=2, kind=None))]), guard=" "None, body=[Expr(value=Constant(value=Ellipsis, " "kind=None))])])], type_ignores=[])") self.assertEqual(dump(tree), norm) if sys.version_info.minor >= 11: def test_TryStar(self): code = ''' try: ... except *ValueError: ...''' norm = ("Module(body=[TryStar(body=[Expr(value=" "Constant(value=Ellipsis))], handlers=[" "ExceptHandler(type=Name(id='ValueError', ctx" "=Load()), body=[Expr(value=Constant(value=" "Ellipsis))])], orelse=[], finalbody=[])], " "type_ignores=[])") pass else: def test_Bytes(self): code = 'b"0012"' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Expr(value=Constant(value=b'0012', " "kind=None))], type_ignores=[])") self.assertEqual(dump(tree), norm) # common def test_TryExcept(self): code = 'try:pass\nexcept e:pass\nelse:pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Try(body=[Pass()], handlers=[ExceptHandler(" "type=Name(id='e', ctx=Load(), annotation=None, " "type_comment=None), name=None, body=[Pass()])]" ", orelse=[Pass()], finalbody=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_TryExceptNamed(self): code = 'try:pass\nexcept e as f:pass\nelse:pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Try(body=[Pass()], handlers=[ExceptHandler(" "type=Name(id='e', ctx=Load(), annotation=None, " "type_comment=None), name=Name(id='f', ctx=" "Store(), annotation=None, type_comment=None), body=[Pass()])]" ", orelse=[Pass()], finalbody=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_Raise(self): codes = ('raise Exception', 'raise "Exception"', 'raise Exception, "err"', 'raise Exception("err")', 'raise E, V, T',) norms = ("Module(body=[Raise(exc=Name(id='Exception', ctx=Load(), " "annotation=None, type_comment=None)," " cause=None)], type_ignores=[])", "Module(body=[Raise(exc=Constant(value='Exception', kind=" "None), cause=None)], type_ignores=[])", "Module(body=[Raise(exc=Call(func=Name(id='Exception', " "ctx=Load(), annotation=None, type_comment=None), " "args=[Constant(value='err', kind=None)], " "keywords=[]), cause=None)], type_ignores=[])", "Module(body=[Raise(exc=Call(func=Name(id='Exception', " "ctx=Load(), annotation=None, type_comment=None), " "args=[Constant(value='err', kind=None)], " "keywords=[]), cause=None)], type_ignores=[])", "Module(body=[Raise(exc=Call(func=Attribute(value=Call(" "func=Name(id='E', ctx=Load(), annotation=None, " "type_comment=None), args=[Name(id='V', ctx=" "Load(), annotation=None, type_comment=None)], keywords=[]), " "attr='with_traceback', ctx=Load" "()), args=[Name(id='T', ctx=Load(), annotation=None, " "type_comment=None)], keywords=[]), " "cause=None)], type_ignores=[])",) if sys.version_info.major == 3: codes = codes[0], codes[1], codes[3] norms = norms[0], norms[1], norms[3] for code, norm in zip(codes, norms): tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') self.assertEqual(dump(tree), norm) def test_Call(self): code = 'foo(x, y=1, *args, **kwargs)' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Expr(value=Call(func=Name(id='foo', ctx=Load" "(), annotation=None, type_comment=None" "), args=[Name(id='x', ctx=Load(), " "annotation=None, type_comment=None), Starred(value=Name(" "id='args', ctx=Load(), annotation=None, type_comment=None)" ", ctx=Load())], keywords=[keyword(" "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(dump(tree), norm) def test_With(self): code = 'with open("any"): pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[With(items=[withitem(context_expr=Call(func=" "Name(id='open', ctx=Load(), annotation=None, " "type_comment=None), args=[Constant(value='any', " "kind=None)], keywords=[]), optional_vars=None)], body=[" "Pass()], type_comment=None)], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_TryFinally(self): code = 'try:pass\nfinally:pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[Try(body=[Pass()], handlers=[], orelse=[], " "finalbody=[Pass()])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_star_argument(self): code = 'def foo(*a): pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[], " "posonlyargs=[], vararg=Name(id='a', ctx=Param(), " "annotation=None, type_comment=None), " "kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), " "body=[Pass()], decorator_list=[], returns=None, " "type_comment=None, type_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_keyword_argument(self): code = 'def foo(**a): pass' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[], " "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_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_Index(self): code = 'def foo(a): a[1]' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[" "Name(id='a', ctx=Param(), annotation=None, type_comment=None)" "], posonlyargs=[], vararg=None, kwonlyargs=[], kw_defaults=[]" ", 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_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_ExtSlice(self): code = 'def foo(a): a[:,:]' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[" "Name(id='a', ctx=Param(), annotation=None, type_comment=None)" "], posonlyargs=[], vararg=None, kwonlyargs=[], kw_defaults=[]" ", kwarg=None, defaults=[]), body=[Expr(value=Subscript(value=" "Name(id='a', ctx=Load(), annotation=None, type_comment=None)" ", 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_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_ExtSlices(self): code = 'def foo(a): a[1,:]' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[" "Name(id='a', ctx=Param(), annotation=None, type_comment=None)" "], posonlyargs=[], vararg=None, kwonlyargs=[], kw_defaults=[]" ", kwarg=None, defaults=[]), body=[Expr(value=Subscript(value=" "Name(id='a', ctx=Load(), annotation=None, type_comment=None)" ", 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_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_Ellipsis(self): code = 'def foo(a): a[...]' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[" "Name(id='a', ctx=Param(), annotation=None, type_comment=None)" "], posonlyargs=[], vararg=None, kwonlyargs=[], kw_defaults=[]" ", 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_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) def test_ExtSliceEllipsis(self): code = 'def foo(a): a[1, ...]' tree = gast.parse(code) compile(gast.gast_to_ast(tree), '', 'exec') norm = ("Module(body=[FunctionDef(name='foo', args=arguments(args=[" "Name(id='a', ctx=Param(), annotation=None, type_comment=None)" "], posonlyargs=[], vararg=None, kwonlyargs=[], kw_defaults=[]" ", kwarg=None, defaults=[]), body=[Expr(value=Subscript(value=" "Name(id='a', ctx=Load(), annotation=None, type_comment=None)" ", 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_params=[])], type_ignores=[])") self.assertEqual(dump(tree), norm) if __name__ == '__main__': unittest.main() gast-0.6.0/tests/test_py3_12.py000066400000000000000000000057661463734575300163020ustar00rootroot00000000000000import 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), '', '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), '', '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), '', '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), '', '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() gast-0.6.0/tests/test_self.py000066400000000000000000000015011463734575300161750ustar00rootroot00000000000000import glob import os import unittest import gast class SelfTestCase(unittest.TestCase): def setUp(self): self.srcs = glob.glob(os.path.join(gast.__path__[0], '*.py')) def testParse(self): for src_py in self.srcs: with open(src_py) as f: content = f.read() gast.parse(content) def testCompile(self): for src_py in self.srcs: with open(src_py) as f: content = f.read() gnode = gast.parse(content) compile(gast.gast_to_ast(gnode), src_py, 'exec') def test_unparse(self): for src_py in self.srcs: with open(src_py) as f: content = f.read() gnode = gast.parse(content) gast.unparse(gnode) if __name__ == '__main__': unittest.main() gast-0.6.0/tests/test_unparser.py000066400000000000000000000016011463734575300171040ustar00rootroot00000000000000import 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), '', '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() gast-0.6.0/tox.ini000066400000000000000000000003101463734575300140010ustar00rootroot00000000000000[tox] envlist = py{27,34,35,36,37,38,39,310, 311, 312},lint [testenv] deps = pytest commands=pytest {posargs} [testenv:lint] deps = pytest-pep8 pytest < 5 commands=pytest --pep8 -m pep8