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 9from typing import Any, Optional, Tuple 10 11 12def ast_dump( 13 node: Any, 14 annotate_fields: bool = True, 15 include_attributes: bool = False, 16 *, 17 indent: Optional[str] = None, 18) -> str: 19 def _format(node: Any, level: int = 0) -> Tuple[str, bool]: 20 if indent is not None: 21 level += 1 22 prefix = "\n" + indent * level 23 sep = ",\n" + indent * level 24 else: 25 prefix = "" 26 sep = ", " 27 if any(cls.__name__ == "AST" for cls in node.__class__.__mro__): 28 cls = type(node) 29 args = [] 30 allsimple = True 31 keywords = annotate_fields 32 for name in node._fields: 33 try: 34 value = getattr(node, name) 35 except AttributeError: 36 keywords = True 37 continue 38 if value is None and getattr(cls, name, ...) is None: 39 keywords = True 40 continue 41 value, simple = _format(value, level) 42 allsimple = allsimple and simple 43 if keywords: 44 args.append("%s=%s" % (name, value)) 45 else: 46 args.append(value) 47 if include_attributes and node._attributes: 48 for name in node._attributes: 49 try: 50 value = getattr(node, name) 51 except AttributeError: 52 continue 53 if value is None and getattr(cls, name, ...) is None: 54 continue 55 value, simple = _format(value, level) 56 allsimple = allsimple and simple 57 args.append("%s=%s" % (name, value)) 58 if allsimple and len(args) <= 3: 59 return "%s(%s)" % (node.__class__.__name__, ", ".join(args)), not args 60 return "%s(%s%s)" % (node.__class__.__name__, prefix, sep.join(args)), False 61 elif isinstance(node, list): 62 if not node: 63 return "[]", True 64 return "[%s%s]" % (prefix, sep.join(_format(x, level)[0] for x in node)), False 65 return repr(node), True 66 67 if all(cls.__name__ != "AST" for cls in node.__class__.__mro__): 68 raise TypeError("expected AST, got %r" % node.__class__.__name__) 69 if indent is not None and not isinstance(indent, str): 70 indent = " " * indent 71 return _format(node)[0] 72