modularize into a directory, hide dot_parser, and flake8 everything
This commit is contained in:
parent
687eb7e18c
commit
9be233d50f
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,3 @@
|
||||
# -*- coding: Latin-1 -*-
|
||||
"""Graphviz's dot language parser.
|
||||
|
||||
The dotparser parses graphviz files in dot and dot files and transforms them
|
||||
@ -16,17 +15,17 @@ __author__ = ['Michael Krause', 'Ero Carrera']
|
||||
__license__ = 'MIT'
|
||||
|
||||
import sys
|
||||
import glob
|
||||
import pydot
|
||||
import re
|
||||
import codecs
|
||||
|
||||
from pyparsing import __version__ as pyparsing_version
|
||||
|
||||
from pyparsing import ( nestedExpr, Literal, CaselessLiteral, Word, Upcase, OneOrMore, ZeroOrMore,
|
||||
Forward, NotAny, delimitedList, oneOf, Group, Optional, Combine, alphas, nums,
|
||||
restOfLine, cStyleComment, nums, alphanums, printables, empty, quotedString,
|
||||
ParseException, ParseResults, CharsNotIn, dblQuotedString, QuotedString, ParserElement )
|
||||
from pyparsing import (
|
||||
nestedExpr, Literal, CaselessLiteral, Word, OneOrMore,
|
||||
Forward, Group, Optional, Combine, nums, restOfLine,
|
||||
cStyleComment, alphanums, printables, ParseException,
|
||||
ParseResults, CharsNotIn, QuotedString
|
||||
)
|
||||
|
||||
|
||||
PY3 = not sys.version_info < (3, 0, 0)
|
||||
@ -38,14 +37,13 @@ if PY3:
|
||||
class P_AttrList:
|
||||
|
||||
def __init__(self, toks):
|
||||
|
||||
self.attrs = {}
|
||||
i = 0
|
||||
|
||||
while i < len(toks):
|
||||
attrname = toks[i]
|
||||
if i+2 < len(toks) and toks[i+1] == '=':
|
||||
attrvalue = toks[i+2]
|
||||
if i + 2 < len(toks) and toks[i + 1] == '=':
|
||||
attrvalue = toks[i + 2]
|
||||
i += 3
|
||||
else:
|
||||
attrvalue = None
|
||||
@ -53,62 +51,54 @@ class P_AttrList:
|
||||
|
||||
self.attrs[attrname] = attrvalue
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
return "%s(%r)" % (self.__class__.__name__, self.attrs)
|
||||
|
||||
|
||||
|
||||
class DefaultStatement(P_AttrList):
|
||||
|
||||
def __init__(self, default_type, attrs):
|
||||
|
||||
self.default_type = default_type
|
||||
self.attrs = attrs
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
return "%s(%s, %r)" % (self.__class__.__name__,
|
||||
self.default_type, self.attrs)
|
||||
return "%s(%s, %r)" % (
|
||||
self.__class__.__name__,
|
||||
self.default_type, self.attrs
|
||||
)
|
||||
|
||||
|
||||
top_graphs = list()
|
||||
|
||||
def push_top_graph_stmt(str, loc, toks):
|
||||
|
||||
def push_top_graph_stmt(str, loc, toks):
|
||||
attrs = {}
|
||||
g = None
|
||||
|
||||
for element in toks:
|
||||
|
||||
if( isinstance(element, (ParseResults, tuple, list)) and
|
||||
len(element) == 1 and isinstance(element[0], basestring) ):
|
||||
|
||||
if (isinstance(element, (ParseResults, tuple, list)) and
|
||||
len(element) == 1 and isinstance(element[0], basestring)):
|
||||
element = element[0]
|
||||
|
||||
if element == 'strict':
|
||||
attrs['strict'] = True
|
||||
|
||||
elif element in ['graph', 'digraph']:
|
||||
|
||||
attrs = {}
|
||||
|
||||
g = pydot.Dot(graph_type=element, **attrs)
|
||||
attrs['type'] = element
|
||||
|
||||
top_graphs.append( g )
|
||||
top_graphs.append(g)
|
||||
|
||||
elif isinstance( element, basestring):
|
||||
g.set_name( element )
|
||||
elif isinstance(element, basestring):
|
||||
g.set_name(element)
|
||||
|
||||
elif isinstance(element, pydot.Subgraph):
|
||||
|
||||
g.obj_dict['attributes'].update( element.obj_dict['attributes'] )
|
||||
g.obj_dict['edges'].update( element.obj_dict['edges'] )
|
||||
g.obj_dict['nodes'].update( element.obj_dict['nodes'] )
|
||||
g.obj_dict['subgraphs'].update( element.obj_dict['subgraphs'] )
|
||||
|
||||
g.obj_dict['attributes'].update(element.obj_dict['attributes'])
|
||||
g.obj_dict['edges'].update(element.obj_dict['edges'])
|
||||
g.obj_dict['nodes'].update(element.obj_dict['nodes'])
|
||||
g.obj_dict['subgraphs'].update(element.obj_dict['subgraphs'])
|
||||
g.set_parent_graph(g)
|
||||
|
||||
elif isinstance(element, P_AttrList):
|
||||
@ -120,24 +110,20 @@ def push_top_graph_stmt(str, loc, toks):
|
||||
else:
|
||||
raise ValueError("Unknown element statement: %r " % element)
|
||||
|
||||
|
||||
for g in top_graphs:
|
||||
update_parent_graph_hierarchy(g)
|
||||
|
||||
if len( top_graphs ) == 1:
|
||||
if len(top_graphs) == 1:
|
||||
return top_graphs[0]
|
||||
|
||||
return top_graphs
|
||||
|
||||
|
||||
def update_parent_graph_hierarchy(g, parent_graph=None, level=0):
|
||||
|
||||
|
||||
if parent_graph is None:
|
||||
parent_graph = g
|
||||
|
||||
for key_name in ('edges',):
|
||||
|
||||
if isinstance(g, pydot.frozendict):
|
||||
item_dict = g
|
||||
else:
|
||||
@ -148,35 +134,31 @@ def update_parent_graph_hierarchy(g, parent_graph=None, level=0):
|
||||
|
||||
for key, objs in item_dict[key_name].items():
|
||||
for obj in objs:
|
||||
if 'parent_graph' in obj and obj['parent_graph'].get_parent_graph()==g:
|
||||
if 'parent_graph' in obj and obj['parent_graph'].get_parent_graph() == g:
|
||||
if obj['parent_graph'] is g:
|
||||
pass
|
||||
else:
|
||||
obj['parent_graph'].set_parent_graph(parent_graph)
|
||||
|
||||
if key_name == 'edges' and len(key) == 2:
|
||||
for idx, vertex in enumerate( obj['points'] ):
|
||||
if isinstance( vertex, (pydot.Graph, pydot.Subgraph, pydot.Cluster)):
|
||||
for idx, vertex in enumerate(obj['points']):
|
||||
if isinstance(vertex, (pydot.Graph, pydot.Subgraph, pydot.Cluster)):
|
||||
vertex.set_parent_graph(parent_graph)
|
||||
if isinstance( vertex, pydot.frozendict):
|
||||
if isinstance(vertex, pydot.frozendict):
|
||||
if vertex['parent_graph'] is g:
|
||||
pass
|
||||
else:
|
||||
vertex['parent_graph'].set_parent_graph(parent_graph)
|
||||
|
||||
|
||||
|
||||
def add_defaults(element, defaults):
|
||||
|
||||
d = element.__dict__
|
||||
for key, value in defaults.items():
|
||||
if not d.get(key):
|
||||
d[key] = value
|
||||
|
||||
|
||||
|
||||
def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge=None):
|
||||
|
||||
if defaults_graph is None:
|
||||
defaults_graph = {}
|
||||
if defaults_node is None:
|
||||
@ -185,41 +167,32 @@ def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge
|
||||
defaults_edge = {}
|
||||
|
||||
for elm_idx, element in enumerate(toks):
|
||||
|
||||
if isinstance(element, (pydot.Subgraph, pydot.Cluster)):
|
||||
|
||||
add_defaults(element, defaults_graph)
|
||||
g.add_subgraph(element)
|
||||
|
||||
elif isinstance(element, pydot.Node):
|
||||
|
||||
add_defaults(element, defaults_node)
|
||||
g.add_node(element)
|
||||
|
||||
elif isinstance(element, pydot.Edge):
|
||||
|
||||
add_defaults(element, defaults_edge)
|
||||
g.add_edge(element)
|
||||
|
||||
elif isinstance(element, ParseResults):
|
||||
|
||||
for e in element:
|
||||
add_elements(g, [e], defaults_graph, defaults_node, defaults_edge)
|
||||
|
||||
elif isinstance(element, DefaultStatement):
|
||||
|
||||
if element.default_type == 'graph':
|
||||
|
||||
default_graph_attrs = pydot.Node('graph', **element.attrs)
|
||||
g.add_node(default_graph_attrs)
|
||||
|
||||
elif element.default_type == 'node':
|
||||
|
||||
default_node_attrs = pydot.Node('node', **element.attrs)
|
||||
g.add_node(default_node_attrs)
|
||||
|
||||
elif element.default_type == 'edge':
|
||||
|
||||
default_edge_attrs = pydot.Node('edge', **element.attrs)
|
||||
g.add_node(default_edge_attrs)
|
||||
defaults_edge.update(element.attrs)
|
||||
@ -228,7 +201,6 @@ def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge
|
||||
raise ValueError("Unknown DefaultStatement: %s " % element.default_type)
|
||||
|
||||
elif isinstance(element, P_AttrList):
|
||||
|
||||
g.obj_dict['attributes'].update(element.attrs)
|
||||
|
||||
else:
|
||||
@ -236,17 +208,16 @@ def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge
|
||||
|
||||
|
||||
def push_graph_stmt(str, loc, toks):
|
||||
|
||||
g = pydot.Subgraph('')
|
||||
add_elements(g, toks)
|
||||
return g
|
||||
|
||||
|
||||
def push_subgraph_stmt(str, loc, toks):
|
||||
|
||||
g = pydot.Subgraph('')
|
||||
|
||||
for e in toks:
|
||||
if len(e)==3:
|
||||
if len(e) == 3:
|
||||
e[2].set_name(e[1])
|
||||
if e[0] == 'subgraph':
|
||||
e[2].obj_dict['show_keyword'] = True
|
||||
@ -260,11 +231,9 @@ def push_subgraph_stmt(str, loc, toks):
|
||||
|
||||
|
||||
def push_default_stmt(str, loc, toks):
|
||||
|
||||
# The pydot class instances should be marked as
|
||||
# default statements to be inherited by actual
|
||||
# graphs, nodes and edges.
|
||||
#
|
||||
default_type = toks[0][0]
|
||||
if len(toks) > 1:
|
||||
attrs = toks[1].attrs
|
||||
@ -278,59 +247,52 @@ def push_default_stmt(str, loc, toks):
|
||||
|
||||
|
||||
def push_attr_list(str, loc, toks):
|
||||
|
||||
p = P_AttrList(toks)
|
||||
return p
|
||||
|
||||
|
||||
def get_port(node):
|
||||
|
||||
if len(node)>1:
|
||||
if len(node) > 1:
|
||||
if isinstance(node[1], ParseResults):
|
||||
if len(node[1][0])==2:
|
||||
if node[1][0][0]==':':
|
||||
if len(node[1][0]) == 2:
|
||||
if node[1][0][0] == ':':
|
||||
return node[1][0][1]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def do_node_ports(node):
|
||||
|
||||
node_port = ''
|
||||
|
||||
if len(node) > 1:
|
||||
node_port = ''.join( [str(a)+str(b) for a,b in node[1] ] )
|
||||
node_port = ''.join([str(a) + str(b) for a, b in node[1]])
|
||||
|
||||
return node_port
|
||||
|
||||
|
||||
def push_edge_stmt(str, loc, toks):
|
||||
|
||||
tok_attrs = [a for a in toks if isinstance(a, P_AttrList)]
|
||||
attrs = {}
|
||||
|
||||
for a in tok_attrs:
|
||||
attrs.update(a.attrs)
|
||||
|
||||
e = []
|
||||
|
||||
if isinstance(toks[0][0], pydot.Graph):
|
||||
|
||||
n_prev = pydot.frozendict(toks[0][0].obj_dict)
|
||||
else:
|
||||
n_prev = toks[0][0] + do_node_ports( toks[0] )
|
||||
n_prev = toks[0][0] + do_node_ports(toks[0])
|
||||
|
||||
if isinstance(toks[2][0], ParseResults):
|
||||
|
||||
n_next_list = [[n.get_name(),] for n in toks[2][0] ]
|
||||
n_next_list = [[n.get_name()] for n in toks[2][0]]
|
||||
for n_next in [n for n in n_next_list]:
|
||||
n_next_port = do_node_ports(n_next)
|
||||
e.append(pydot.Edge(n_prev, n_next[0]+n_next_port, **attrs))
|
||||
e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs))
|
||||
|
||||
elif isinstance(toks[2][0], pydot.Graph):
|
||||
|
||||
e.append(pydot.Edge(n_prev, pydot.frozendict(toks[2][0].obj_dict), **attrs))
|
||||
|
||||
elif isinstance(toks[2][0], pydot.Node):
|
||||
|
||||
node = toks[2][0]
|
||||
|
||||
if node.get_port() is not None:
|
||||
@ -341,16 +303,14 @@ def push_edge_stmt(str, loc, toks):
|
||||
e.append(pydot.Edge(n_prev, name_port, **attrs))
|
||||
|
||||
elif isinstance(toks[2][0], type('')):
|
||||
|
||||
for n_next in [n for n in tuple(toks)[2::2]]:
|
||||
|
||||
if isinstance(n_next, P_AttrList) or not isinstance(n_next[0], type('')):
|
||||
continue
|
||||
|
||||
n_next_port = do_node_ports( n_next )
|
||||
e.append(pydot.Edge(n_prev, n_next[0]+n_next_port, **attrs))
|
||||
n_next_port = do_node_ports(n_next)
|
||||
e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs))
|
||||
|
||||
n_prev = n_next[0]+n_next_port
|
||||
n_prev = n_next[0] + n_next_port
|
||||
|
||||
else:
|
||||
# UNEXPECTED EDGE TYPE
|
||||
@ -359,7 +319,6 @@ def push_edge_stmt(str, loc, toks):
|
||||
return e
|
||||
|
||||
|
||||
|
||||
def push_node_stmt(s, loc, toks):
|
||||
|
||||
if len(toks) == 2:
|
||||
@ -369,27 +328,22 @@ def push_node_stmt(s, loc, toks):
|
||||
|
||||
node_name = toks[0]
|
||||
if isinstance(node_name, list) or isinstance(node_name, tuple):
|
||||
if len(node_name)>0:
|
||||
if len(node_name) > 0:
|
||||
node_name = node_name[0]
|
||||
|
||||
n = pydot.Node(str(node_name), **attrs)
|
||||
return n
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
graphparser = None
|
||||
|
||||
def graph_definition():
|
||||
|
||||
def graph_definition():
|
||||
global graphparser
|
||||
|
||||
if not graphparser:
|
||||
|
||||
# punctuation
|
||||
colon = Literal(":")
|
||||
colon = Literal(":")
|
||||
lbrace = Literal("{")
|
||||
rbrace = Literal("}")
|
||||
lbrack = Literal("[")
|
||||
@ -397,29 +351,28 @@ def graph_definition():
|
||||
lparen = Literal("(")
|
||||
rparen = Literal(")")
|
||||
equals = Literal("=")
|
||||
comma = Literal(",")
|
||||
dot = Literal(".")
|
||||
slash = Literal("/")
|
||||
bslash = Literal("\\")
|
||||
star = Literal("*")
|
||||
semi = Literal(";")
|
||||
at = Literal("@")
|
||||
minus = Literal("-")
|
||||
comma = Literal(",")
|
||||
# dot = Literal(".")
|
||||
# slash = Literal("/")
|
||||
# bslash = Literal("\\")
|
||||
# star = Literal("*")
|
||||
semi = Literal(";")
|
||||
at = Literal("@")
|
||||
minus = Literal("-")
|
||||
|
||||
# keywords
|
||||
strict_ = CaselessLiteral("strict")
|
||||
graph_ = CaselessLiteral("graph")
|
||||
digraph_ = CaselessLiteral("digraph")
|
||||
subgraph_ = CaselessLiteral("subgraph")
|
||||
node_ = CaselessLiteral("node")
|
||||
edge_ = CaselessLiteral("edge")
|
||||
|
||||
strict_ = CaselessLiteral("strict")
|
||||
graph_ = CaselessLiteral("graph")
|
||||
digraph_ = CaselessLiteral("digraph")
|
||||
subgraph_ = CaselessLiteral("subgraph")
|
||||
node_ = CaselessLiteral("node")
|
||||
edge_ = CaselessLiteral("edge")
|
||||
|
||||
# token definitions
|
||||
identifier = Word(alphanums + "_.").setName("identifier")
|
||||
|
||||
identifier = Word(alphanums + "_." ).setName("identifier")
|
||||
|
||||
double_quoted_string = QuotedString('"', multiline=True, unquoteResults=False) # dblQuotedString
|
||||
# dblQuotedString
|
||||
double_quoted_string = QuotedString('"', multiline=True, unquoteResults=False)
|
||||
|
||||
noncomma_ = "".join([c for c in printables if c != ","])
|
||||
alphastring_ = OneOrMore(CharsNotIn(noncomma_ + ' '))
|
||||
@ -427,46 +380,56 @@ def graph_definition():
|
||||
def parse_html(s, loc, toks):
|
||||
return '<%s>' % ''.join(toks[0])
|
||||
|
||||
|
||||
opener = '<'
|
||||
closer = '>'
|
||||
html_text = nestedExpr( opener, closer,
|
||||
( CharsNotIn( opener + closer ) )
|
||||
).setParseAction(parse_html).leaveWhitespace()
|
||||
html_text = nestedExpr(
|
||||
opener, closer,
|
||||
(CharsNotIn(opener + closer))
|
||||
).setParseAction(parse_html).leaveWhitespace()
|
||||
|
||||
ID = ( identifier | html_text |
|
||||
double_quoted_string | #.setParseAction(strip_quotes) |
|
||||
alphastring_ ).setName("ID")
|
||||
ID = (
|
||||
identifier | html_text |
|
||||
double_quoted_string | # .setParseAction(strip_quotes) |
|
||||
alphastring_
|
||||
).setName("ID")
|
||||
|
||||
float_number = Combine(
|
||||
Optional(minus) +
|
||||
OneOrMore(Word(nums + "."))
|
||||
).setName("float_number")
|
||||
|
||||
float_number = Combine(Optional(minus) +
|
||||
OneOrMore(Word(nums + "."))).setName("float_number")
|
||||
|
||||
righthand_id = (float_number | ID ).setName("righthand_id")
|
||||
righthand_id = (float_number | ID).setName("righthand_id")
|
||||
|
||||
port_angle = (at + ID).setName("port_angle")
|
||||
|
||||
port_location = (OneOrMore(Group(colon + ID)) |
|
||||
Group(colon + lparen + ID + comma + ID + rparen)).setName("port_location")
|
||||
port_location = (
|
||||
OneOrMore(Group(colon + ID)) |
|
||||
Group(colon + lparen + ID + comma + ID + rparen)
|
||||
).setName("port_location")
|
||||
|
||||
port = (Group(port_location + Optional(port_angle)) |
|
||||
Group(port_angle + Optional(port_location))).setName("port")
|
||||
port = (
|
||||
Group(port_location + Optional(port_angle)) |
|
||||
Group(port_angle + Optional(port_location))
|
||||
).setName("port")
|
||||
|
||||
node_id = (ID + Optional(port))
|
||||
a_list = OneOrMore(ID + Optional(equals + righthand_id) +
|
||||
Optional(comma.suppress())).setName("a_list")
|
||||
a_list = OneOrMore(
|
||||
ID + Optional(equals + righthand_id) + Optional(comma.suppress())
|
||||
).setName("a_list")
|
||||
|
||||
attr_list = OneOrMore(lbrack.suppress() + Optional(a_list) +
|
||||
rbrack.suppress()).setName("attr_list")
|
||||
attr_list = OneOrMore(
|
||||
lbrack.suppress() + Optional(a_list) + rbrack.suppress()
|
||||
).setName("attr_list")
|
||||
|
||||
attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt")
|
||||
|
||||
edgeop = (Literal("--") | Literal("->")).setName("edgeop")
|
||||
|
||||
stmt_list = Forward()
|
||||
graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) +
|
||||
rbrace.suppress() + Optional(semi.suppress()) ).setName("graph_stmt")
|
||||
|
||||
graph_stmt = Group(
|
||||
lbrace.suppress() + Optional(stmt_list) +
|
||||
rbrace.suppress() + Optional(semi.suppress())
|
||||
).setName("graph_stmt")
|
||||
|
||||
edge_point = Forward()
|
||||
|
||||
@ -475,22 +438,27 @@ def graph_definition():
|
||||
|
||||
subgraph = Group(subgraph_ + Optional(ID) + graph_stmt).setName("subgraph")
|
||||
|
||||
edge_point << Group( subgraph | graph_stmt | node_id ).setName('edge_point')
|
||||
edge_point << Group(subgraph | graph_stmt | node_id).setName('edge_point')
|
||||
|
||||
node_stmt = (node_id + Optional(attr_list) + Optional(semi.suppress())).setName("node_stmt")
|
||||
node_stmt = (
|
||||
node_id + Optional(attr_list) + Optional(semi.suppress())
|
||||
).setName("node_stmt")
|
||||
|
||||
assignment = (ID + equals + righthand_id).setName("assignment")
|
||||
stmt = (assignment | edge_stmt | attr_stmt | subgraph | graph_stmt | node_stmt).setName("stmt")
|
||||
stmt = (
|
||||
assignment | edge_stmt | attr_stmt |
|
||||
subgraph | graph_stmt | node_stmt
|
||||
).setName("stmt")
|
||||
stmt_list << OneOrMore(stmt + Optional(semi.suppress()))
|
||||
|
||||
graphparser = OneOrMore( (Optional(strict_) + Group((graph_ | digraph_)) +
|
||||
Optional(ID) + graph_stmt).setResultsName("graph") )
|
||||
graphparser = OneOrMore((
|
||||
Optional(strict_) + Group((graph_ | digraph_)) +
|
||||
Optional(ID) + graph_stmt
|
||||
).setResultsName("graph"))
|
||||
|
||||
singleLineComment = Group("//" + restOfLine) | Group("#" + restOfLine)
|
||||
|
||||
|
||||
# actions
|
||||
|
||||
graphparser.ignore(singleLineComment)
|
||||
graphparser.ignore(cStyleComment)
|
||||
|
||||
@ -504,12 +472,10 @@ def graph_definition():
|
||||
graph_stmt.setParseAction(push_graph_stmt)
|
||||
graphparser.setParseAction(push_top_graph_stmt)
|
||||
|
||||
|
||||
return graphparser
|
||||
|
||||
|
||||
def parse_dot_data(data):
|
||||
|
||||
global top_graphs
|
||||
|
||||
top_graphs = list()
|
||||
@ -549,6 +515,6 @@ def parse_dot_data(data):
|
||||
except ParseException:
|
||||
err = sys.exc_info()[1]
|
||||
print(err.line)
|
||||
print(" "*(err.column-1) + "^")
|
||||
print(" " * (err.column - 1) + "^")
|
||||
print(err)
|
||||
return None
|
36
setup.py
36
setup.py
@ -11,25 +11,29 @@ import os
|
||||
os.environ['COPY_EXTENDED_ATTRIBUTES_DISABLE'] = 'true'
|
||||
os.environ['COPYFILE_DISABLE'] = 'true'
|
||||
|
||||
setup( name = 'pydot',
|
||||
version = pydot.__version__,
|
||||
description = 'Python interface to Graphviz\'s Dot',
|
||||
author = 'Ero Carrera',
|
||||
author_email = 'ero@dkbza.org',
|
||||
url = 'http://code.google.com/p/pydot/',
|
||||
download_url = 'http://pydot.googlecode.com/files/pydot-%s.tar.gz' % pydot.__version__,
|
||||
license = 'MIT',
|
||||
keywords = 'graphviz dot graphs visualization',
|
||||
platforms = ['any'],
|
||||
classifiers = ['Development Status :: 5 - Production/Stable',
|
||||
setup(
|
||||
name='pydot',
|
||||
version=pydot.__version__,
|
||||
description='Python interface to Graphviz\'s Dot',
|
||||
author='Ero Carrera',
|
||||
author_email='ero@dkbza.org',
|
||||
url='http://code.google.com/p/pydot/',
|
||||
download_url='http://pydot.googlecode.com/files/pydot-%s.tar.gz' % pydot.__version__,
|
||||
license='MIT',
|
||||
keywords='graphviz dot graphs visualization',
|
||||
platforms=['any'],
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Science/Research',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Topic :: Scientific/Engineering :: Visualization',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules'],
|
||||
long_description = "\n".join(pydot.__doc__.split('\n')),
|
||||
py_modules = ['pydot', 'dot_parser'],
|
||||
install_requires = ['pyparsing'],
|
||||
data_files = [('.', ['LICENSE', 'README'])] )
|
||||
'Topic :: Software Development :: Libraries :: Python Modules'
|
||||
],
|
||||
long_description="\n".join(pydot.__doc__.split('\n')),
|
||||
packages=['pydot'],
|
||||
package_dir={'pydot': 'pydot'},
|
||||
requires=['pyparsing (>=2.0.1)'],
|
||||
)
|
||||
|
@ -17,7 +17,6 @@ import subprocess
|
||||
import sys
|
||||
|
||||
import pydot
|
||||
import dot_parser
|
||||
import unittest
|
||||
|
||||
|
||||
@ -30,11 +29,11 @@ else:
|
||||
NULL_SEP = ''
|
||||
bytes = str
|
||||
|
||||
DOT_BINARY_PATH = pydot.find_graphviz()['dot']
|
||||
TEST_DIR = './'
|
||||
REGRESSION_TESTS_DIR = os.path.join(TEST_DIR, 'graphs')
|
||||
MY_REGRESSION_TESTS_DIR = os.path.join(TEST_DIR, 'my_tests')
|
||||
|
||||
DOT_BINARY_PATH = pydot.find_graphviz()['dot']
|
||||
TEST_DIR = './'
|
||||
REGRESSION_TESTS_DIR = os.path.join(TEST_DIR, 'graphs')
|
||||
MY_REGRESSION_TESTS_DIR = os.path.join(TEST_DIR, 'my_tests')
|
||||
|
||||
|
||||
class TestGraphAPI(unittest.TestCase):
|
||||
@ -43,35 +42,29 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
|
||||
def _reset_graphs(self):
|
||||
|
||||
self.graph_directed = pydot.Graph('testgraph', graph_type='digraph')
|
||||
|
||||
|
||||
def test_keep_graph_type(self):
|
||||
|
||||
g = pydot.Dot(graph_name='Test', graph_type='graph')
|
||||
|
||||
self.assertEqual( g.get_type(), 'graph' )
|
||||
self.assertEqual(g.get_type(), 'graph')
|
||||
|
||||
g = pydot.Dot(graph_name='Test', graph_type='digraph')
|
||||
|
||||
self.assertEqual( g.get_type(), 'digraph' )
|
||||
|
||||
self.assertEqual(g.get_type(), 'digraph')
|
||||
|
||||
def test_add_style(self):
|
||||
|
||||
g = pydot.Dot(graph_name='Test', graph_type='graph')
|
||||
|
||||
node = pydot.Node('mynode')
|
||||
node.add_style('abc')
|
||||
self.assertEqual( node.get_style(), 'abc' )
|
||||
self.assertEqual(node.get_style(), 'abc')
|
||||
node.add_style('def')
|
||||
self.assertEqual( node.get_style(), 'abc,def' )
|
||||
self.assertEqual(node.get_style(), 'abc,def')
|
||||
node.add_style('ghi')
|
||||
self.assertEqual( node.get_style(), 'abc,def,ghi' )
|
||||
|
||||
self.assertEqual(node.get_style(), 'abc,def,ghi')
|
||||
|
||||
def test_create_simple_graph_with_node(self):
|
||||
|
||||
@ -80,33 +73,30 @@ class TestGraphAPI(unittest.TestCase):
|
||||
node = pydot.Node('legend')
|
||||
node.set("shape", 'box')
|
||||
g.add_node(node)
|
||||
node.set('label','mine')
|
||||
|
||||
self.assertEqual( g.to_string(), 'digraph G {\nlegend [label=mine, shape=box];\n}\n' )
|
||||
node.set('label', 'mine')
|
||||
|
||||
self.assertEqual(g.to_string(), 'digraph G {\nlegend [label=mine, shape=box];\n}\n')
|
||||
|
||||
def test_attribute_with_implicit_value(self):
|
||||
|
||||
d='digraph {\na -> b[label="hi", decorate];\n}'
|
||||
d = 'digraph {\na -> b[label="hi", decorate];\n}'
|
||||
g = pydot.graph_from_dot_data(d)
|
||||
attrs = g.get_edges()[0].get_attributes()
|
||||
|
||||
self.assertEqual( 'decorate' in attrs, True )
|
||||
|
||||
self.assertEqual('decorate' in attrs, True)
|
||||
|
||||
def test_subgraphs(self):
|
||||
|
||||
g = pydot.Graph()
|
||||
s = pydot.Subgraph("foo")
|
||||
|
||||
self.assertEqual( g.get_subgraphs(), [] )
|
||||
self.assertEqual( g.get_subgraph_list(), [] )
|
||||
self.assertEqual(g.get_subgraphs(), [])
|
||||
self.assertEqual(g.get_subgraph_list(), [])
|
||||
|
||||
g.add_subgraph(s)
|
||||
|
||||
self.assertEqual( g.get_subgraphs()[0].get_name(), s.get_name() )
|
||||
self.assertEqual( g.get_subgraph_list()[0].get_name(), s.get_name() )
|
||||
|
||||
self.assertEqual(g.get_subgraphs()[0].get_name(), s.get_name())
|
||||
self.assertEqual(g.get_subgraph_list()[0].get_name(), s.get_name())
|
||||
|
||||
def test_graph_pickling(self):
|
||||
|
||||
@ -115,14 +105,12 @@ class TestGraphAPI(unittest.TestCase):
|
||||
g = pydot.Graph()
|
||||
s = pydot.Subgraph("foo")
|
||||
g.add_subgraph(s)
|
||||
g.add_edge( pydot.Edge('A','B') )
|
||||
g.add_edge( pydot.Edge('A','C') )
|
||||
g.add_edge( pydot.Edge( ('D','E') ) )
|
||||
g.add_node( pydot.Node( 'node!' ) )
|
||||
|
||||
self.assertEqual( type(pickle.dumps(g)), bytes )
|
||||
|
||||
g.add_edge(pydot.Edge('A', 'B'))
|
||||
g.add_edge(pydot.Edge('A', 'C'))
|
||||
g.add_edge(pydot.Edge(('D', 'E')))
|
||||
g.add_node(pydot.Node('node!'))
|
||||
|
||||
self.assertEqual(type(pickle.dumps(g)), bytes)
|
||||
|
||||
def test_unicode_ids(self):
|
||||
|
||||
@ -131,72 +119,69 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
g = pydot.Dot()
|
||||
g.set_charset('latin1')
|
||||
g.add_node( pydot.Node( node1 ) )
|
||||
g.add_node( pydot.Node( node2 ) )
|
||||
g.add_edge( pydot.Edge( node1, node2 ) )
|
||||
g.add_node(pydot.Node(node1))
|
||||
g.add_node(pydot.Node(node2))
|
||||
g.add_edge(pydot.Edge(node1, node2))
|
||||
|
||||
self.assertEqual( g.get_node(node1)[0].get_name(), node1 )
|
||||
self.assertEqual( g.get_node(node2)[0].get_name(), node2 )
|
||||
self.assertEqual(g.get_node(node1)[0].get_name(), node1)
|
||||
self.assertEqual(g.get_node(node2)[0].get_name(), node2)
|
||||
|
||||
self.assertEqual( g.get_edges()[0].get_source(), node1 )
|
||||
self.assertEqual( g.get_edges()[0].get_destination(), node2 )
|
||||
self.assertEqual(g.get_edges()[0].get_source(), node1)
|
||||
self.assertEqual(g.get_edges()[0].get_destination(), node2)
|
||||
|
||||
#g2 = dot_parser.parse_dot_data( g.to_string() )
|
||||
g2 = pydot.graph_from_dot_data( g.to_string() )
|
||||
g2 = pydot.graph_from_dot_data(g.to_string())
|
||||
|
||||
self.assertEqual( g2.get_node(node1)[0].get_name(), node1 )
|
||||
self.assertEqual( g2.get_node(node2)[0].get_name(), node2 )
|
||||
|
||||
self.assertEqual( g2.get_edges()[0].get_source(), node1 )
|
||||
self.assertEqual( g2.get_edges()[0].get_destination(), node2 )
|
||||
self.assertEqual(g2.get_node(node1)[0].get_name(), node1)
|
||||
self.assertEqual(g2.get_node(node2)[0].get_name(), node2)
|
||||
|
||||
self.assertEqual(g2.get_edges()[0].get_source(), node1)
|
||||
self.assertEqual(g2.get_edges()[0].get_destination(), node2)
|
||||
|
||||
def test_graph_with_shapefiles(self):
|
||||
|
||||
shapefile_dir = os.path.join(TEST_DIR, 'from-past-to-future')
|
||||
dot_file = os.path.join( shapefile_dir, 'from-past-to-future.dot' )
|
||||
dot_file = os.path.join(shapefile_dir, 'from-past-to-future.dot')
|
||||
|
||||
pngs = [
|
||||
os.path.join(shapefile_dir, fname)
|
||||
for fname in os.listdir(shapefile_dir)
|
||||
if fname.endswith('.png')
|
||||
]
|
||||
|
||||
pngs = dot_files = [ os.path.join(shapefile_dir, fname) for
|
||||
fname in os.listdir(shapefile_dir) if fname.endswith('.png') ]
|
||||
|
||||
f = open( dot_file, 'rt' )
|
||||
f = open(dot_file, 'rt')
|
||||
graph_data = f.read()
|
||||
f.close()
|
||||
|
||||
#g = dot_parser.parse_dot_data(graph_data)
|
||||
g = pydot.graph_from_dot_data(graph_data)
|
||||
|
||||
g.set_shape_files( pngs )
|
||||
g.set_shape_files(pngs)
|
||||
|
||||
jpe_data = g.create( format='jpe' )
|
||||
jpe_data = g.create(format='jpe')
|
||||
|
||||
hexdigest = sha256(jpe_data).hexdigest()
|
||||
|
||||
hexdigest_original = self._render_with_graphviz(dot_file)
|
||||
|
||||
self.assertEqual( hexdigest, hexdigest_original )
|
||||
|
||||
self.assertEqual(hexdigest, hexdigest_original)
|
||||
|
||||
def test_multiple_graphs(self):
|
||||
|
||||
graph_data = 'graph A { a->b };\ngraph B {c->d}'
|
||||
|
||||
#graphs = dot_parser.parse_dot_data(graph_data)
|
||||
graphs = pydot.graph_from_dot_data(graph_data)
|
||||
|
||||
self.assertEqual( len(graphs), 2 )
|
||||
|
||||
self.assertEqual( [g.get_name() for g in graphs], ['A', 'B'] )
|
||||
self.assertEqual(len(graphs), 2)
|
||||
|
||||
self.assertEqual([g.get_name() for g in graphs], ['A', 'B'])
|
||||
|
||||
def _render_with_graphviz(self, filename):
|
||||
|
||||
p = subprocess.Popen(
|
||||
( DOT_BINARY_PATH , '-Tjpe', ),
|
||||
(DOT_BINARY_PATH, '-Tjpe'),
|
||||
cwd=os.path.dirname(filename),
|
||||
stdin=open(filename, 'rt'),
|
||||
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
stderr=subprocess.PIPE, stdout=subprocess.PIPE
|
||||
)
|
||||
|
||||
stdout = p.stdout
|
||||
|
||||
@ -212,48 +197,41 @@ class TestGraphAPI(unittest.TestCase):
|
||||
stdout_output = NULL_SEP.join(stdout_output)
|
||||
|
||||
#pid, status = os.waitpid(p.pid, 0)
|
||||
status = p.wait()
|
||||
# this returns a status code we should check
|
||||
p.wait()
|
||||
|
||||
return sha256(stdout_output).hexdigest()
|
||||
|
||||
|
||||
def _render_with_pydot(self, filename):
|
||||
|
||||
#f = open(filename, 'rt')
|
||||
#graph_data = f.read()
|
||||
#f.close()
|
||||
|
||||
#g = dot_parser.parse_dot_data(graph_data)
|
||||
#g = pydot.parse_from_dot_data(graph_data)
|
||||
g = pydot.graph_from_dot_file(filename)
|
||||
|
||||
if not isinstance( g, list ):
|
||||
if not isinstance(g, list):
|
||||
g = [g]
|
||||
|
||||
jpe_data = NULL_SEP.join( [ _g.create( format='jpe' ) for _g in g ] )
|
||||
jpe_data = NULL_SEP.join([_g.create(format='jpe') for _g in g])
|
||||
|
||||
return sha256(jpe_data).hexdigest()
|
||||
|
||||
|
||||
def test_my_regression_tests(self):
|
||||
|
||||
self._render_and_compare_dot_files( MY_REGRESSION_TESTS_DIR )
|
||||
|
||||
self._render_and_compare_dot_files(MY_REGRESSION_TESTS_DIR)
|
||||
|
||||
def test_graphviz_regression_tests(self):
|
||||
|
||||
self._render_and_compare_dot_files( REGRESSION_TESTS_DIR )
|
||||
|
||||
self._render_and_compare_dot_files(REGRESSION_TESTS_DIR)
|
||||
|
||||
def _render_and_compare_dot_files(self, directory):
|
||||
|
||||
dot_files = [ fname for fname in os.listdir(directory) if
|
||||
fname.endswith('.dot') ] ##and fname.startswith('')]
|
||||
dot_files = [
|
||||
fname for fname in os.listdir(directory)
|
||||
if fname.endswith('.dot')
|
||||
] # and fname.startswith('')]
|
||||
|
||||
for dot in dot_files:
|
||||
|
||||
#print 'Processing: %s' % dot
|
||||
|
||||
os.sys.stdout.write('#')
|
||||
os.sys.stdout.flush()
|
||||
|
||||
@ -261,7 +239,6 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
try:
|
||||
parsed_data_hexdigest = self._render_with_pydot(fname)
|
||||
|
||||
original_data_hexdigest = self._render_with_graphviz(fname)
|
||||
except Exception:
|
||||
print('Failed rendering BAD(%s)' % dot)
|
||||
@ -271,122 +248,106 @@ class TestGraphAPI(unittest.TestCase):
|
||||
if parsed_data_hexdigest != original_data_hexdigest:
|
||||
print('BAD(%s)' % dot)
|
||||
|
||||
self.assertEqual( parsed_data_hexdigest, original_data_hexdigest )
|
||||
|
||||
|
||||
self.assertEqual(parsed_data_hexdigest, original_data_hexdigest)
|
||||
|
||||
def test_numeric_node_id(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node( pydot.Node(1) )
|
||||
|
||||
self.assertEqual( self.graph_directed.get_nodes()[0].get_name() , '1' )
|
||||
self.graph_directed.add_node(pydot.Node(1))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].get_name(), '1')
|
||||
|
||||
def test_quoted_node_id(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node( pydot.Node('"node"') )
|
||||
|
||||
self.assertEqual( self.graph_directed.get_nodes()[0].get_name() , '"node"' )
|
||||
self.graph_directed.add_node(pydot.Node('"node"'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].get_name(), '"node"')
|
||||
|
||||
def test_quoted_node_id_to_string_no_attributes(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node( pydot.Node('"node"') )
|
||||
self.graph_directed.add_node(pydot.Node('"node"'))
|
||||
|
||||
self.assertEqual( self.graph_directed.get_nodes()[0].to_string() , '"node";' )
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].to_string(), '"node";')
|
||||
|
||||
def test_keyword_node_id(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node( pydot.Node('node') )
|
||||
|
||||
self.assertEqual( self.graph_directed.get_nodes()[0].get_name() , 'node' )
|
||||
self.graph_directed.add_node(pydot.Node('node'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].get_name(), 'node')
|
||||
|
||||
def test_keyword_node_id_to_string_no_attributes(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node( pydot.Node('node') )
|
||||
|
||||
self.assertEqual( self.graph_directed.get_nodes()[0].to_string() , '' )
|
||||
self.graph_directed.add_node(pydot.Node('node'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].to_string(), '')
|
||||
|
||||
def test_keyword_node_id_to_string_with_attributes(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node( pydot.Node('node', shape='box') )
|
||||
|
||||
self.assertEqual( self.graph_directed.get_nodes()[0].to_string() , 'node [shape=box];' )
|
||||
self.graph_directed.add_node(pydot.Node('node', shape='box'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].to_string(), 'node [shape=box];')
|
||||
|
||||
def test_names_of_a_thousand_nodes(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
names = set([ 'node_%05d' % i for i in xrange(10**4) ])
|
||||
names = set(['node_%05d' % i for i in xrange(10 ** 4)])
|
||||
|
||||
for name in names:
|
||||
|
||||
self.graph_directed.add_node( pydot.Node(name, label=name) )
|
||||
|
||||
self.assertEqual( set([ n.get_name() for n in self.graph_directed.get_nodes() ]), names )
|
||||
self.graph_directed.add_node(pydot.Node(name, label=name))
|
||||
|
||||
self.assertEqual(set([n.get_name() for n in self.graph_directed.get_nodes()]), names)
|
||||
|
||||
def test_executable_not_found_exception(self):
|
||||
|
||||
|
||||
paths = {'dot': 'invalid_executable_path'}
|
||||
|
||||
graph = pydot.Dot( 'graphname', graph_type='digraph' )
|
||||
graph = pydot.Dot('graphname', graph_type='digraph')
|
||||
|
||||
graph.set_graphviz_executables( paths )
|
||||
|
||||
self.assertRaises( pydot.InvocationException, graph.create )
|
||||
graph.set_graphviz_executables(paths)
|
||||
|
||||
self.assertRaises(pydot.InvocationException, graph.create)
|
||||
|
||||
def test_graph_add_node_argument_type(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.assertRaises( TypeError, self.graph_directed.add_node, 1 )
|
||||
self.assertRaises( TypeError, self.graph_directed.add_node, 'a' )
|
||||
|
||||
self.assertRaises(TypeError, self.graph_directed.add_node, 1)
|
||||
self.assertRaises(TypeError, self.graph_directed.add_node, 'a')
|
||||
|
||||
def test_graph_add_edge_argument_type(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.assertRaises( TypeError, self.graph_directed.add_edge, 1 )
|
||||
self.assertRaises( TypeError, self.graph_directed.add_edge, 'a' )
|
||||
|
||||
self.assertRaises(TypeError, self.graph_directed.add_edge, 1)
|
||||
self.assertRaises(TypeError, self.graph_directed.add_edge, 'a')
|
||||
|
||||
def test_graph_add_subgraph_argument_type(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.assertRaises( TypeError, self.graph_directed.add_subgraph, 1 )
|
||||
self.assertRaises( TypeError, self.graph_directed.add_subgraph, 'a' )
|
||||
|
||||
self.assertRaises(TypeError, self.graph_directed.add_subgraph, 1)
|
||||
self.assertRaises(TypeError, self.graph_directed.add_subgraph, 'a')
|
||||
|
||||
def test_quoting(self):
|
||||
import string
|
||||
g = pydot.Dot()
|
||||
g.add_node(pydot.Node("test", label=string.printable))
|
||||
#print g.to_string()
|
||||
data = g.create( format='jpe' )
|
||||
self.assertEqual( len(data) > 0, True )
|
||||
data = g.create(format='jpe')
|
||||
self.assertEqual(len(data) > 0, True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase( TestGraphAPI )
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestGraphAPI)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
|
Loading…
x
Reference in New Issue
Block a user