Пример #1
0
def flatten_ast(node: Any, prefix="", path="") -> str:
    if isinstance(node, ast.AST):
        acc = [f"{prefix}/_type={type(node).__name__}\n"]
        if isinstance(node, ast.expr):
            node_repr = remove_context("", ast.dump(node))
            expr_hash = hex(hash(node_repr) & 0xFFFFFFFF)
            acc.append(f"{prefix}/_hash={expr_hash}\n")
        if "lineno" in node._attributes:
            acc.append(f"{prefix}/_pos={node.lineno}:{path[2:]}\n")
        fields = ast.iter_fields(node)
        if isinstance(node, ast.FunctionDef):
            # reject `body` behind `decorator_list` and `returns`, whose line number is those of `def` clause
            fields = iter(sorted(fields, key=lambda c: c[0] == "body"))
        for (i, (name, x)) in enumerate(fields):
            if name == "orelse" and isinstance(node, (ast.For, ast.While, ast.AsyncFor)):
                name = "loopelse"  # this makes the "orelse" clause specific to conditionals
            elif name == "targets" and isinstance(node, ast.Assign):
                name = "assigntargets"
            elif name == "target" and isinstance(node, ast.AugAssign):
                name = "assigntarget"
            elif name == "value" and isinstance(node, (ast.Assign, ast.AugAssign)):
                name = "assignvalue"
            acc.append(flatten_ast(x, f"{prefix}/{name}", f"{path}{i}-"))
        return "".join(acc)
    elif isinstance(node, list):
        acc = [f"{prefix}/length={len(node)}\n"]
        for (i, x) in enumerate(node, 1):
            acc.append(flatten_ast(x, f"{prefix}/{i}", f"{path}{i}-"))
        return "".join(acc)
    elif prefix.endswith(("/s", "/module")):
        return f"""{prefix}={repr(node)}\n"""
    else:
        return f"""{prefix}={repr(node).strip("'")}\n"""
Пример #2
0
    def generic_visit(self, node):

        if isinstance(node, list):
            nodestart = "["
            nodeend = "]"
            children = [("", child) for child in node]
        else:
            nodestart = type(node).__name__ + "("
            nodeend = ")"
            children = [(name + "=", value) for name, value in ast.iter_fields(node)]

        if len(children) > 1:
            self.indentation += 1

        self.write(nodestart)
        for i, pair in enumerate(children):
            attr, child = pair
            if len(children) > 1:
                self.write("\n" + self.indent_with * self.indentation)
            if isinstance(child, (ast.AST, list)):
                self.write(attr)
                self.visit(child)
            else:
                self.write(attr + repr(child))

            if i != len(children) - 1:
                self.write(",")
        self.write(nodeend)

        if len(children) > 1:
            self.indentation -= 1
Пример #3
0
def flatten_node(
    node: Any,
    prefix: str = "",
    path: str = "",
    remove_context: Callable = regex.compile(r", ctx=.+?\(\)").sub,
) -> str:
    r"""Traverse recursively (in pre-order) the given AST node and flatten its subtree.

    Args:
        node (Any): The node to traverse. Initially, the whole AST.
        prefix (str, optional): The prefix of the current line to dump. Defaults to `""`.
        path (str, optional): The path of the current node. Defaults to `""`.
        remove_context (Callable, optional): A function removing the node context encoded in the
            result of `ast3.dump()`.
            [Not to be explicitly provided.](developer_manual/index.html#default-argument-trick)
            Defaults to `regex.compile(r", ctx=.+?\(\)").sub`.

    Returns:
        str: A flat representation of the given node.
    """
    if isinstance(node, ast.AST):
        acc = [f"{prefix}/_type={type(node).__name__}\n"]
        if isinstance(node, ast.expr):
            node_repr = remove_context("", ast.dump(node))
            acc.append(f"{prefix}/_hash={pseudo_hash(node_repr)}\n")
        if "lineno" in node._attributes:
            acc.append(f"{prefix}/_pos={node.lineno}:{path[2:]}\n")
        fields = ast.iter_fields(node)
        if isinstance(node, ast.FunctionDef):
            # make `body` the last item of a `def` clause
            fields = iter(sorted(fields, key=lambda c: c[0] == "body"))
        for (i, (name, x)) in enumerate(fields):
            if name == "orelse" and isinstance(
                    node, (ast.For, ast.While, ast.AsyncFor)):
                name = "loopelse"  # make the `orelse` clause specific to conditionals
            elif name == "targets" and isinstance(node, ast.Assign):
                name = "assigntargets"  # `targets` is also used for `Delete`, etc.
            elif name == "target" and isinstance(node, ast.AugAssign):
                name = "assigntarget"  # `target` is also used for comprehension, etc.
            elif name == "value" and isinstance(node,
                                                (ast.Assign, ast.AugAssign)):
                name = "assignvalue"  # `value` is also used for comprehension, etc.
            acc.append(flatten_node(x, f"{prefix}/{name}", f"{path}{i}-"))
        return "".join(acc)
    elif isinstance(node, list):
        acc = [f"{prefix}/_length={len(node)}\n"]
        for (i, x) in enumerate(node, 1):  # number the children from 1
            acc.append(flatten_node(x, f"{prefix}/{i}", f"{path}{i}-"))
        return "".join(acc)
    else:
        # If the node is a terminal value, dump it unquoted
        return f"""{prefix}={repr(node).strip("'")}\n"""
Пример #4
0
 def generic_visit(self, node):
     """Copied implementation from parent class - get rid of it at some point."""
     if not self._fields_first:
         _LOG.debug('visiting node %s', node)
         node = self.visit_node(node)
         if not hasattr(node, '_fields'):
             return node
     _LOG.debug('visiting all fields of node %s', node)
     for name, value in typed_ast3.iter_fields(node):
         setattr(node, name, self.generic_visit_field(node, name, value))
     if self._fields_first:
         _LOG.debug('visiting node %s', node)
         node = self.visit_node(node)
     return node
Пример #5
0
def ast_to_string(ast_node, line_indent=''):
    next_line_indent = line_indent + '  '

    if isinstance(ast_node, ast.AST):
        return (ast_node.__class__.__name__ + '(' + ','.join(
            '\n' + next_line_indent + field_name + ' = ' +
            ast_to_string(child_node, next_line_indent)
            for field_name, child_node in ast.iter_fields(ast_node)) + ')')
    elif isinstance(ast_node, list):
        return ('[' + ','.join('\n' + next_line_indent +
                               ast_to_string(child_node, next_line_indent)
                               for child_node in ast_node) + ']')
    else:
        return repr(ast_node)
Пример #6
0
 def helper(v: Any) -> Any:
     "Takes a `typed_ast.AST` and converts it into a python ast.AST"
     if isinstance(v, ast3.AST):
         cls = getattr(ast, type(v).__name__)
         return cls(**{
             f: typed_ast3_to_ast(node)
             for f, node in ast3.iter_fields(v)
         })
     elif isinstance(v, list):
         return [typed_ast3_to_ast(e) for e in v]
     elif isinstance(v, (str, int, float)) or v is None:
         return v
     raise AstTransformerError(
         "typed_ast3_to_ast: The type '{}' is unknown to me".format(
             type(v)))
Пример #7
0
 def helper(v: Any) -> Any:
     "Takes a `typed_ast.AST` and converts it into a python ast.AST"
     if isinstance(v, ast3.AST):
         cls = type(v)
         new_v = cls(
             **{f: copy_ast3(node)
                for f, node in ast3.iter_fields(v)})
         if hasattr(v, 'ctx'):
             new_v.ctx = v.ctx  # type: ignore
         return ast3.copy_location(new_v, v)
     elif isinstance(v, list):
         return [copy_ast3(e) for e in v]
     elif isinstance(v, (str, int, float)) or v is None:
         return v
     raise AstTransformerError(
         "typed_ast3_to_ast: The type '{}' is unknown to me".format(
             type(v)))
Пример #8
0
 def generic_visit(self, node):
     for field, old_value in ast3.iter_fields(node):
         if isinstance(old_value, list):
             new_values = []
             for value in old_value:
                 if isinstance(value, ast3.AST):
                     value = self.visit(value)
                     if value is None:
                         continue
                     elif not isinstance(value, ast.AST):
                         new_values.extend(value)
                         continue
                 new_values.append(value)
             old_value[:] = new_values
         elif isinstance(old_value, ast3.AST):
             new_node = self.visit(old_value)
             if new_node is None:
                 delattr(node, field)
             else:
                 setattr(node, field, new_node)
     return node
Пример #9
0
 def _format(node, level=0):
     if isinstance(node, AST):
         fields = [(a, _format(b, level)) for a, b in iter_fields(node)]
         rv = '%s(%s' % (node.__class__.__name__, ', '.join(
             ('%s=%s' % field for field in fields) if annotate_fields else
             (b for a, b in fields)))
         if include_attributes and node._attributes:
             rv += fields and ', ' or ' '
             rv += ', '.join('%s=%s' % (a, _format(getattr(node, a)))
                             for a in node._attributes)
         return rv + ')'
     elif isinstance(node, list):
         lines = ['[']
         lines.extend((indent * (level + 2) + _format(x, level + 2) + ','
                       for x in node))
         if len(lines) > 1:
             lines.append(indent * (level + 1) + ']')
         else:
             lines[-1] += ']'
         return '\n'.join(lines)
     return repr(node)
Пример #10
0
def print_node_value(node, str):
    for f in ast3.iter_fields(node):
        print(str)
        print(f)