Files
deb-python-taskflow/tools/state_graph.py
Joshua Harlow 5ca61f956e Add a directed graph type (new types module)
Most of the utility graph functions we have can
be connected to a directed graph class that itself
derives (and adds on to) the networkx base class.

Doing this allows for functionality that isn't exposed
in networkx to be exposed in our subclass (which is a
useful pattern to have).

It also makes it possible (if ever needed) to replace
the networkx usage in taskflow with something else if
this ever becomes a major request.

Change-Id: I0a825d5637236d7b5dbdbda0d426adb0183d5ba3
2014-04-20 17:28:27 -07:00

80 lines
2.4 KiB
Python

#!/usr/bin/env python
import os
import sys
top_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
os.pardir))
sys.path.insert(0, top_dir)
import optparse
import subprocess
import tempfile
from taskflow import states
from taskflow.types import graph as gr
def mini_exec(cmd, ok_codes=(0,)):
stdout = subprocess.PIPE
stderr = subprocess.PIPE
proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr, stdin=None)
(stdout, stderr) = proc.communicate()
rc = proc.returncode
if rc not in ok_codes:
raise RuntimeError("Could not run %s [%s]\nStderr: %s"
% (cmd, rc, stderr))
return (stdout, stderr)
def make_svg(graph, output_filename, output_format):
# NOTE(harlowja): requires pydot!
gdot = graph.export_to_dot()
if output_format == 'dot':
output = gdot
elif output_format in ('svg', 'svgz', 'png'):
with tempfile.NamedTemporaryFile(suffix=".dot") as fh:
fh.write(gdot)
fh.flush()
cmd = ['dot', '-T%s' % output_format, fh.name]
output, _stderr = mini_exec(cmd)
else:
raise ValueError('Unknown format: %s' % output_filename)
with open(output_filename, "wb") as fh:
fh.write(output)
def main():
parser = optparse.OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="write svg to FILE", metavar="FILE")
parser.add_option("-t", "--tasks", dest="tasks",
action='store_true',
help="use task state transitions",
default=False)
parser.add_option("-T", "--format", dest="format",
help="output in given format",
default='svg')
(options, args) = parser.parse_args()
if options.filename is None:
options.filename = 'states.%s' % options.format
g = gr.DiGraph(name="State transitions")
if not options.tasks:
source = states._ALLOWED_FLOW_TRANSITIONS
else:
source = states._ALLOWED_TASK_TRANSITIONS
for (u, v) in source:
if not g.has_node(u):
g.add_node(u)
if not g.has_node(v):
g.add_node(v)
g.add_edge(u, v)
make_svg(g, options.filename, options.format)
print("Created %s at '%s'" % (options.format, options.filename))
if __name__ == '__main__':
main()