# -*- coding: utf-8; -*- """Dump an AST into a string, with pythonic indentation. Based on Alex Leone's `astpp.py`, with changes to indentation logic. http://alexleone.blogspot.co.uk/2010/01/python-ast-pretty-printer.html """ __all__ = ["dump"] from ast import AST, iter_fields from .colorizer import colorize, ColorScheme NoneType = type(None) def dump(tree, *, include_attributes=False, multiline=True, color=False): """Return a formatted dump of `tree`, as a string. `tree` can be an AST node or a statement suite (`list` of AST nodes). Attributes such as line numbers and column offsets are not dumped by default. If this is wanted, use `include_attributes=True`. To use indentation similar to how the code to construct the AST would appear as Python source code, use `multiline=True`. To put everything on one line, use `multiline=False`. If you're printing the result into a terminal, consider `color=True`. Similar to `macropy`'s `real_repr`, but with indentation. The method `ast.AST.__repr__` itself can't be monkey-patched, because `ast.AST` is a built-in/extension type. """ def maybe_colorize(text, *colors): if not color: return text return colorize(text, *colors) def maybe_colorize_value(value): if type(value) in (str, bytes, NoneType, bool, int, float, complex): # Pass through an already formatted list-as-a-string from an inner level. if isinstance(value, str) and value.startswith("["): return value return maybe_colorize(str(value), ColorScheme.BAREVALUE) return str(value) def recurse(tree, previndent=0): def separator(): if multiline: return f",\n{(previndent + moreindent) * ' '}" return ", " if isinstance(tree, AST): moreindent = len(f"{tree.__class__.__name__}(") fields = [(k, recurse(v, previndent + moreindent + len(f"{k}="))) for k, v in iter_fields(tree)] if include_attributes and tree._attributes: fields.extend([(k, recurse(getattr(tree, k, None), previndent + moreindent + len(f"{k}="))) for k in tree._attributes]) colorized_fields = [(maybe_colorize(k, ColorScheme.FIELDNAME), maybe_colorize_value(v)) for k, v in fields] return "".join([ maybe_colorize(tree.__class__.__name__, ColorScheme.NODETYPE), "(", separator().join((f"{k}={v}" for k, v in colorized_fields)), ")"]) elif isinstance(tree, list): moreindent = len("[") items = [recurse(elt, previndent + moreindent) for elt in tree] if items: items[0] = "[" + items[0].lstrip() items[-1] = items[-1] + "]" return separator().join(items) return "[]" return repr(tree) if not isinstance(tree, (AST, list)): raise TypeError(f"expected AST, got {tree.__class__.__name__!r}") return recurse(tree)