Source code for minivect.graphviz
"""
Visitor to generate a Graphviz .dot file with an AST representation.
"""
from pydot import pydot
import minivisitor
[docs]class GraphvizGenerator(minivisitor.PrintTree):
"""
Render a minivect AST as a graphviz tree.
"""
def __init__(self, context, name, node_color=None, edge_color=None,
node_fontcolor=None, edge_fontcolor=None):
super(GraphvizGenerator, self).__init__(context)
self.name = name
self.counter = 0
self.node_color = node_color
self.edge_color = edge_color
self.node_fontcolor = node_fontcolor
self.edge_fontcolor = edge_fontcolor
[docs] def create_node(self, node):
"Create a graphviz node from the miniast node"
label = '"%s"' % self.format_node(node, want_type_info=False)
self.counter += 1
pydot_node = pydot.Node(str(self.counter), label=label)
self.add_node(pydot_node)
return pydot_node
[docs] def add_node(self, pydot_node):
"Add a pydot node to the graph and set its colors"
if self.node_color is not None:
pydot_node.set_color(self.node_color)
if self.node_fontcolor is not None:
pydot_node.set_fontcolor(self.node_fontcolor)
self.graph.add_node(pydot_node)
[docs] def add_edge(self, source, dest, edge_label=None):
"Add an edge between two pydot nodes and set the colors"
edge = pydot.Edge(source, dest)
if edge_label is not None:
edge.set_label(edge_label)
if self.edge_color is not None:
edge.set_color(self.edge_color)
if self.edge_fontcolor is not None:
edge.set_fontcolor(self.edge_fontcolor)
self.graph.add_edge(edge)
[docs] def visit_Node(self, node, pydot_node=None):
"Visit children and add edges to their Graphviz nodes."
if pydot_node is None:
pydot_node = self.create_node(node)
nodes_dict = self.visitchildren(node)
attrs = self.context.getchildren(node)
for attr in attrs:
values = nodes_dict.get(attr, None)
if values is not None:
if isinstance(values, list):
for value in values:
self.add_edge(pydot_node, value)
else:
self.add_edge(pydot_node, values, attr)
return pydot_node
[docs] def visit_FunctionNode(self, node):
"Create a graphviz graph"
self.graph = pydot.Dot(self.name, graph_type='digraph')
pydot_function = self.create_node(node)
pydot_body = self.visit(node.body)
# Create artificial arguments for brevity
pydot_args = pydot.Node("Arguments (omitted)")
self.add_node(pydot_args)
self.add_edge(pydot_function, pydot_body)
self.add_edge(pydot_function, pydot_args)
return self.graph