Welcome, guest | Sign In | My Account | Store | Cart

A function that outputs a human-readable version of a Python AST.

Python, 64 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"""Python AST pretty-printer.

This module exports a function that can be used to print a human-readable
version of the AST.
"""
__author__ = 'Martin Blais <blais@furius.ca>'

import sys
from compiler.ast import Node

__all__ = ('printAst',)


def printAst(ast, indent='  ', stream=sys.stdout, initlevel=0):
    "Pretty-print an AST to the given output stream."
    rec_node(ast, initlevel, indent, stream.write)
    stream.write('\n')

def rec_node(node, level, indent, write):
    "Recurse through a node, pretty-printing it."
    pfx = indent * level
    if isinstance(node, Node):
        write(pfx)
        write(node.__class__.__name__)
        write('(')

        if any(isinstance(child, Node) for child in node.getChildren()):
            for i, child in enumerate(node.getChildren()):
                if i != 0:
                    write(',')
                write('\n')
                rec_node(child, level+1, indent, write)
            write('\n')
            write(pfx)
        else:
            # None of the children as nodes, simply join their repr on a single
            # line.
            write(', '.join(repr(child) for child in node.getChildren()))

        write(')')

    else:
        write(pfx)
        write(repr(node))


def main():
    import optparse
    parser = optparse.OptionParser(__doc__.strip())
    opts, args = parser.parse_args()

    if not args:
        parser.error("You need to specify the name of Python files to print out.")

    import compiler, traceback
    for fn in args:
        print '\n\n%s:\n' % fn
        try:
            printAst(compiler.parseFile(fn), initlevel=1)
        except SyntaxError, e:
            traceback.print_exc()

if __name__ == '__main__':
    main()

To me, it is totally unbelievable that the standard Python compiler module does not come with a pretty-printer for the AST. It just blows my mind, completely. I don't know how many times I have been hacking around one until today.

You can find the latest version of this code in the Snakefood project source or here:: http://furius.ca/pubcode/

This really should belong in the standard compiler module (and that code should be improved too, the visitors are always a PIA to use).