• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Copy-parse of ast.dump, removing the `isinstance` checks. This is needed,
3because testing pegen requires generating a C extension module, which contains
4a copy of the symbols defined in Python-ast.c. Thus, the isinstance check would
5always fail. We rely on string comparison of the base classes instead.
6TODO: Remove the above-described hack.
7"""
8
9
10def ast_dump(node, annotate_fields=True, include_attributes=False, *, indent=None):
11    def _format(node, level=0):
12        if indent is not None:
13            level += 1
14            prefix = "\n" + indent * level
15            sep = ",\n" + indent * level
16        else:
17            prefix = ""
18            sep = ", "
19        if any(cls.__name__ == "AST" for cls in node.__class__.__mro__):
20            cls = type(node)
21            args = []
22            allsimple = True
23            keywords = annotate_fields
24            for name in node._fields:
25                try:
26                    value = getattr(node, name)
27                except AttributeError:
28                    keywords = True
29                    continue
30                if value is None and getattr(cls, name, ...) is None:
31                    keywords = True
32                    continue
33                value, simple = _format(value, level)
34                allsimple = allsimple and simple
35                if keywords:
36                    args.append("%s=%s" % (name, value))
37                else:
38                    args.append(value)
39            if include_attributes and node._attributes:
40                for name in node._attributes:
41                    try:
42                        value = getattr(node, name)
43                    except AttributeError:
44                        continue
45                    if value is None and getattr(cls, name, ...) is None:
46                        continue
47                    value, simple = _format(value, level)
48                    allsimple = allsimple and simple
49                    args.append("%s=%s" % (name, value))
50            if allsimple and len(args) <= 3:
51                return "%s(%s)" % (node.__class__.__name__, ", ".join(args)), not args
52            return "%s(%s%s)" % (node.__class__.__name__, prefix, sep.join(args)), False
53        elif isinstance(node, list):
54            if not node:
55                return "[]", True
56            return "[%s%s]" % (prefix, sep.join(_format(x, level)[0] for x in node)), False
57        return repr(node), True
58
59    if all(cls.__name__ != "AST" for cls in node.__class__.__mro__):
60        raise TypeError("expected AST, got %r" % node.__class__.__name__)
61    if indent is not None and not isinstance(indent, str):
62        indent = " " * indent
63    return _format(node)[0]
64