Source code for ctree.dotgen
import ast
from ctree.visitors import NodeVisitor
from ctree.util import enumerate_flatten
[docs]def label_for_py_ast_nodes(self):
from ctree.py.dotgen import PyDotLabeller
return PyDotLabeller().visit(self)
[docs]def to_dot_outer_for_py_ast_nodes(self):
return "digraph mytree {\n%s}" % self._to_dot()
[docs]def to_dot_inner_for_py_ast_nodes(self):
from ctree.dotgen import DotGenVisitor
return DotGenVisitor().visit(self)
"""
Bind to_dot_for_py_ast_nodes to all classes that derive from ast.AST. Ideally
we'd be able to bind one method to ast.AST, but it's a built-in type so we
can't.
"""
for entry in ast.__dict__.values():
try:
if issubclass(entry, ast.AST):
entry.label = label_for_py_ast_nodes
entry.to_dot = to_dot_outer_for_py_ast_nodes
entry._to_dot = to_dot_inner_for_py_ast_nodes
except TypeError:
pass
[docs]class DotGenLabeller(NodeVisitor):
[docs] def generic_visit(self, node):
return ""
[docs]class DotGenVisitor(NodeVisitor):
"""
Generates a representation of the AST in the DOT graph language.
See http://en.wikipedia.org/wiki/DOT_(graph_description_language)
"""
def __init__(self):
self._visited = []
@staticmethod
def _qualified_name(obj):
"""
return object name with leading module
"""
return "%s.%s" % (obj.__module__, obj.__name__)
[docs] def label(self, node):
"""
A string to provide useful information for visualization, debugging, etc.
"""
return r"%s\n%s" % (type(node).__name__, node.label())
[docs] def generic_visit(self, node):
# abort if visited
if node in self._visited:
return ""
else:
self._visited.append(node)
# label this node
out_string = 'n%s [label="%s"];\n' % (id(node), self.label(node))
# edges to children
for fieldname, fieldvalue in ast.iter_fields(node):
for index, child in enumerate_flatten(fieldvalue):
if isinstance(child, ast.AST):
suffix = "".join(["[%d]" % i for i in index])
out_string += 'n%d -> n%d [label="%s%s"];\n' % (id(node), id(child), fieldname, suffix)
out_string += self.visit(child)
return out_string