diff --git a/dot_parser.py b/dot_parser.py index 90d97e2..a6b8ee0 100644 --- a/dot_parser.py +++ b/dot_parser.py @@ -37,7 +37,6 @@ class P_AttrList(object): def __init__(self, toks): - self.attrs = {} i = 0 @@ -52,30 +51,25 @@ def __init__(self, toks): 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) + 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 @@ -97,17 +91,17 @@ def push_top_graph_stmt(str, loc, toks): g = pydot.Dot(graph_type=element, **attrs) attrs['type'] = element - top_graphs.append( g ) + top_graphs.append(g) - elif isinstance( element, str_type): - g.set_name( element ) + elif isinstance(element, str_type): + 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) @@ -121,19 +115,16 @@ def push_top_graph_stmt(str, loc, toks): raise ValueError( 'Unknown element statement: {s}'.format(s=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 @@ -150,19 +141,19 @@ 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): + 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, + 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: @@ -170,19 +161,15 @@ def update_parent_graph_hierarchy(g, parent_graph=None, level=0): 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: @@ -246,17 +233,15 @@ def add_elements(g, toks, defaults_graph=None, 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 @@ -270,7 +255,6 @@ 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. @@ -289,33 +273,29 @@ 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: @@ -327,11 +307,11 @@ def push_edge_stmt(str, loc, toks): 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)) @@ -362,7 +342,7 @@ def push_edge_stmt(str, loc, toks): not isinstance(n_next[0], str_type)): continue - n_next_port = do_node_ports( n_next ) + 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 @@ -374,9 +354,7 @@ def push_edge_stmt(str, loc, toks): return e - def push_node_stmt(s, loc, toks): - if len(toks) == 2: attrs = toks[1].attrs else: @@ -384,27 +362,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("[") @@ -412,30 +385,29 @@ def graph_definition(): lparen = Literal("(") rparen = Literal(")") equals = Literal("=") - comma = Literal(",") - dot = Literal(".") - slash = Literal("/") + comma = Literal(",") + dot = Literal(".") + slash = Literal("/") bslash = Literal("\\") - star = Literal("*") - semi = Literal(";") - at = Literal("@") - minus = 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, escChar='\\') # dblQuotedString + '"', multiline=True, unquoteResults=False, escChar='\\' + ) noncomma = "".join([c for c in printables if c != ","]) alphastring_ = OneOrMore(CharsNotIn(noncomma + ' ')) @@ -443,38 +415,46 @@ 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 | + 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") - - attr_list = OneOrMore(lbrack.suppress() + Optional(a_list) + - rbrack.suppress()).setName("attr_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_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt") @@ -482,10 +462,12 @@ def parse_html(s, loc, toks): edgeop = (Literal("--") | Literal("->")).setName("edgeop") stmt_list = Forward() - graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) + + graph_stmt = Group( + lbrace.suppress() + + Optional(stmt_list) + rbrace.suppress() + - Optional(semi.suppress())).setName("graph_stmt") - + Optional(semi.suppress()) + ).setName("graph_stmt") edge_point = Forward() @@ -514,7 +496,6 @@ def parse_html(s, loc, toks): singleLineComment = Group( "//" + restOfLine) | Group("#" + restOfLine) - # actions graphparser.ignore(singleLineComment) @@ -530,7 +511,6 @@ def parse_html(s, loc, toks): graph_stmt.setParseAction(push_graph_stmt) graphparser.setParseAction(push_top_graph_stmt) - return graphparser diff --git a/pydot.py b/pydot.py index e3f7c6a..c8c461d 100644 --- a/pydot.py +++ b/pydot.py @@ -32,7 +32,8 @@ str_type = basestring -GRAPH_ATTRIBUTES = { 'Damping', 'K', 'URL', 'aspect', 'bb', 'bgcolor', +GRAPH_ATTRIBUTES = { + 'Damping', 'K', 'URL', 'aspect', 'bb', 'bgcolor', 'center', 'charset', 'clusterrank', 'colorscheme', 'comment', 'compound', 'concentrate', 'defaultdist', 'dim', 'dimen', 'diredgeconstraints', 'dpi', 'epsilon', 'esep', 'fontcolor', 'fontname', 'fontnames', @@ -47,10 +48,12 @@ 'showboxes', 'size', 'smoothing', 'sortv', 'splines', 'start', 'stylesheet', 'target', 'truecolor', 'viewport', 'voro_margin', # for subgraphs - 'rank' } + 'rank' +} -EDGE_ATTRIBUTES = { 'URL', 'arrowhead', 'arrowsize', 'arrowtail', +EDGE_ATTRIBUTES = { + 'URL', 'arrowhead', 'arrowsize', 'arrowtail', 'color', 'colorscheme', 'comment', 'constraint', 'decorate', 'dir', 'edgeURL', 'edgehref', 'edgetarget', 'edgetooltip', 'fontcolor', 'fontname', 'fontsize', 'headURL', 'headclip', 'headhref', 'headlabel', @@ -61,10 +64,12 @@ 'nojustify', 'penwidth', 'pos', 'samehead', 'sametail', 'showboxes', 'style', 'tailURL', 'tailclip', 'tailhref', 'taillabel', 'tailport', 'tailtarget', 'tailtooltip', 'target', 'tooltip', 'weight', - 'rank' } + 'rank' +} -NODE_ATTRIBUTES = { 'URL', 'color', 'colorscheme', 'comment', +NODE_ATTRIBUTES = { + 'URL', 'color', 'colorscheme', 'comment', 'distortion', 'fillcolor', 'fixedsize', 'fontcolor', 'fontname', 'fontsize', 'group', 'height', 'id', 'image', 'imagescale', 'label', 'labelloc', 'layer', 'margin', 'nojustify', 'orientation', 'penwidth', @@ -72,13 +77,16 @@ 'shape', 'shapefile', 'showboxes', 'sides', 'skew', 'sortv', 'style', 'target', 'tooltip', 'vertices', 'width', 'z', # The following are attributes dot2tex - 'texlbl', 'texmode' } + 'texlbl', 'texmode' +} -CLUSTER_ATTRIBUTES = { 'K', 'URL', 'bgcolor', 'color', 'colorscheme', +CLUSTER_ATTRIBUTES = { + 'K', 'URL', 'bgcolor', 'color', 'colorscheme', 'fillcolor', 'fontcolor', 'fontname', 'fontsize', 'label', 'labeljust', 'labelloc', 'lheight', 'lp', 'lwidth', 'nojustify', 'pencolor', - 'penwidth', 'peripheries', 'sortv', 'style', 'target', 'tooltip' } + 'penwidth', 'peripheries', 'sortv', 'style', 'target', 'tooltip' +} DEFAULT_PROGRAMS = { @@ -99,7 +107,8 @@ def is_windows(): def is_anaconda(): # type: () -> bool import glob - return glob.glob(os.path.join(sys.prefix, 'conda-meta\\graphviz*.json')) != [] + conda_pattern = os.path.join(sys.prefix, 'conda-meta\\graphviz*.json') + return glob.glob(conda_pattern) != [] def get_executable_extension(): @@ -151,6 +160,7 @@ def call_graphviz(program, arguments, working_dir, **kwargs): # This version freezes dictionaries used as values within dictionaries. # class frozendict(dict): + def _blocked_attribute(obj): raise AttributeError('A frozendict cannot be modified.') _blocked_attribute = property(_blocked_attribute) @@ -175,13 +185,13 @@ def __new__(cls, *args, **kw): v_ = list() for elm in v: if isinstance(elm, dict): - v_.append( frozendict(elm) ) + v_.append(frozendict(elm)) else: - v_.append( elm ) + v_.append(elm) arg[k] = tuple(v_) - args_.append( arg ) + args_.append(arg) else: - args_.append( arg ) + args_.append(arg) dict.__init__(new, *args_, **kw) return new @@ -207,11 +217,11 @@ def __repr__(self): '^[_a-zA-Z][a-zA-Z0-9_,:\"]*[a-zA-Z0-9_,\"]+$', re.UNICODE) id_re_num = re.compile('^[0-9,]+$', re.UNICODE) id_re_with_port = re.compile('^([^:]*):([^:]*)$', re.UNICODE) -id_re_dbl_quoted = re.compile('^\".*\"$', re.S|re.UNICODE) -id_re_html = re.compile('^<.*>$', re.S|re.UNICODE) +id_re_dbl_quoted = re.compile('^\".*\"$', re.S | re.UNICODE) +id_re_html = re.compile('^<.*>$', re.S | re.UNICODE) -def needs_quotes( s ): +def needs_quotes(s): """Checks whether a string is a dot language ID. It will check whether the string is solely composed @@ -230,7 +240,7 @@ def needs_quotes( s ): if s in dot_keywords: return False - chars = [ord(c) for c in s if ord(c)>0x7f or ord(c)==0] + chars = [ord(c) for c in s if ord(c) > 0x7f or ord(c) == 0] if chars and not id_re_dbl_quoted.match(s) and not id_re_html.match(s): return True @@ -254,17 +264,17 @@ def quote_if_necessary(s): return 'True' return 'False' - if not isinstance( s, str_type): + if not isinstance(s, str_type): return s if not s: return s if needs_quotes(s): - replace = {'"' : r'\"', - "\n" : r'\n', - "\r" : r'\r'} - for (a,b) in replace.items(): + replace = {'"': r'\"', + "\n": r'\n', + "\r": r'\r'} + for (a, b) in replace.items(): s = s.replace(a, b) return '"' + s + '"' @@ -272,7 +282,6 @@ def quote_if_necessary(s): return s - def graph_from_dot_data(s): """Load graphs from DOT description in string `s`. @@ -303,7 +312,6 @@ def graph_from_dot_file(path, encoding=None): return graphs - def graph_from_edges(edge_list, node_prefix='', directed=False): """Creates a basic graph out of an edge list. @@ -333,13 +341,13 @@ def graph_from_edges(edge_list, node_prefix='', directed=False): else: dst = node_prefix + str(edge[1]) - e = Edge( src, dst ) + e = Edge(src, dst) graph.add_edge(e) return graph -def graph_from_adjacency_matrix(matrix, node_prefix= u'', directed=False): +def graph_from_adjacency_matrix(matrix, node_prefix=u'', directed=False): """Creates a basic graph out of an adjacency matrix. The matrix has to be a list of rows of values @@ -384,8 +392,6 @@ def graph_from_incidence_matrix(matrix, node_prefix='', directed=False): as they can evaluate to True or False. """ - node_orig = 1 - if directed: graph = Dot(graph_type='digraph') else: @@ -419,24 +425,17 @@ class Common(object): this one. """ - def __getstate__(self): - dict = copy.copy(self.obj_dict) - return dict - def __setstate__(self, state): - self.obj_dict = state - def __get_attribute__(self, attr): """Look for default attributes for this node""" attr_val = self.obj_dict['attributes'].get(attr, None) - if attr_val is None: # get the defaults for nodes/edges @@ -448,7 +447,7 @@ def __get_attribute__(self, attr): g = self.get_parent_graph() if g is not None: - defaults = g.get_node( default_node_name ) + defaults = g.get_node(default_node_name) else: return None @@ -472,17 +471,12 @@ def __get_attribute__(self, attr): return None - def set_parent_graph(self, parent_graph): - self.obj_dict['parent_graph'] = parent_graph - def get_parent_graph(self): - return self.obj_dict.get('parent_graph', None) - def set(self, name, value): """Set an attribute value by name. @@ -493,10 +487,8 @@ def set(self, name, value): which are defined for all the existing attributes. """ - self.obj_dict['attributes'][name] = value - def get(self, name): """Get an attribute value by name. @@ -507,50 +499,44 @@ def get(self, name): which are defined for all the existing attributes. """ - return self.obj_dict['attributes'].get(name, None) - def get_attributes(self): - """""" - + """Get attributes of the object""" return self.obj_dict['attributes'] - def set_sequence(self, seq): - + """Set sequence""" self.obj_dict['sequence'] = seq - def get_sequence(self): - + """Get sequence""" return self.obj_dict['sequence'] - def create_attribute_methods(self, obj_attributes): - - #for attr in self.obj_dict['attributes']: for attr in obj_attributes: - # Generate all the Setter methods. # self.__setattr__( 'set_'+attr, - lambda x, a=attr : - self.obj_dict['attributes'].__setitem__(a, x) ) + lambda x, a=attr: + self.obj_dict['attributes'].__setitem__(a, x) + ) # Generate all the Getter methods. # self.__setattr__( - 'get_'+attr, lambda a=attr : self.__get_attribute__(a)) - + 'get_'+attr, lambda a=attr: self.__get_attribute__(a) + ) class Error(Exception): """General error handling class. """ + def __init__(self, value): self.value = value + def __str__(self): return self.value @@ -558,13 +544,14 @@ def __str__(self): class InvocationException(Exception): """Indicate problem while running any GraphViz executable. """ + def __init__(self, value): self.value = value + def __str__(self): return self.value - class Node(Common): """A graph node. @@ -578,15 +565,13 @@ class Node(Common): be supported. """ - def __init__(self, name = '', obj_dict = None, **attrs): - + def __init__(self, name='', obj_dict=None, **attrs): # # Nodes will take attributes of # all other types because the defaults # for any GraphViz object are dealt with # as if they were Node definitions # - if obj_dict is not None: self.obj_dict = obj_dict @@ -597,11 +582,11 @@ def __init__(self, name = '', obj_dict = None, **attrs): # Copy the attributes # - self.obj_dict[ 'attributes' ] = dict( attrs ) - self.obj_dict[ 'type' ] = 'node' - self.obj_dict[ 'parent_graph' ] = None - self.obj_dict[ 'parent_node_list' ] = None - self.obj_dict[ 'sequence' ] = None + self.obj_dict['attributes'] = dict(attrs) + self.obj_dict['type'] = 'node' + self.obj_dict['parent_graph'] = None + self.obj_dict['parent_node_list'] = None + self.obj_dict['sequence'] = None # Remove the compass point # @@ -622,41 +607,30 @@ def __init__(self, name = '', obj_dict = None, **attrs): def __str__(self): return self.to_string() - def set_name(self, node_name): """Set the node's name.""" - self.obj_dict['name'] = node_name - def get_name(self): """Get the node's name.""" - return self.obj_dict['name'] - def get_port(self): """Get the node's port.""" - return self.obj_dict['port'] - def add_style(self, style): - styles = self.obj_dict['attributes'].get('style', None) if not styles and style: - styles = [ style ] + styles = [style] else: styles = styles.split(',') - styles.append( style ) - - self.obj_dict['attributes']['style'] = ','.join( styles ) + styles.append(style) + self.obj_dict['attributes']['style'] = ','.join(styles) def to_string(self): """Return string representation of node in DOT language.""" - - # RMF: special case defaults for node, edge and graph properties. # node = quote_if_necessary(self.obj_dict['name']) @@ -669,10 +643,10 @@ def to_string(self): value = '""' if value is not None: node_attr.append( - '%s=%s' % (attr, quote_if_necessary(value) ) ) + '%s=%s' % (attr, quote_if_necessary(value)) + ) else: - node_attr.append( attr ) - + node_attr.append(attr) # No point in having nodes setting any defaults if the don't set # any attributes... @@ -688,7 +662,6 @@ def to_string(self): return node + ';' - class Edge(Common): """A graph edge. @@ -729,11 +702,11 @@ def __init__(self, src='', dst='', obj_dict=None, **attrs): self.obj_dict['points'] = points if obj_dict is None: # Copy the attributes - self.obj_dict[ 'attributes' ] = dict( attrs ) - self.obj_dict[ 'type' ] = 'edge' - self.obj_dict[ 'parent_graph' ] = None - self.obj_dict[ 'parent_edge_list' ] = None - self.obj_dict[ 'sequence' ] = None + self.obj_dict['attributes'] = dict(attrs) + self.obj_dict['type'] = 'edge' + self.obj_dict['parent_graph'] = None + self.obj_dict['parent_edge_list'] = None + self.obj_dict['sequence'] = None else: self.obj_dict = obj_dict self.create_attribute_methods(EDGE_ATTRIBUTES) @@ -741,24 +714,18 @@ def __init__(self, src='', dst='', obj_dict=None, **attrs): def __str__(self): return self.to_string() - def get_source(self): """Get the edges source node name.""" - return self.obj_dict['points'][0] - def get_destination(self): """Get the edge's destination node name.""" - return self.obj_dict['points'][1] - def __hash__(self): - - return hash( hash(self.get_source()) + - hash(self.get_destination()) ) - + return hash( + hash(self.get_source()) + hash(self.get_destination()) + ) def __eq__(self, edge): """Compare two edges. @@ -780,16 +747,15 @@ def __eq__(self, edge): # If the graph is undirected, the edge has neither # source nor destination. # - if ( ( self.get_source() == edge.get_source() and - self.get_destination() == edge.get_destination() ) or - ( edge.get_source() == self.get_destination() and - edge.get_destination() == self.get_source() ) ): + if ((self.get_source() == edge.get_source() and + self.get_destination() == edge.get_destination()) or + (edge.get_source() == self.get_destination() and + edge.get_destination() == self.get_source())): return True else: - - if (self.get_source()==edge.get_source() and - self.get_destination()==edge.get_destination()): + if (self.get_source() == edge.get_source() and + self.get_destination() == edge.get_destination()): return True return False @@ -802,7 +768,6 @@ def __ne__(self, other): return not result def parse_node_ref(self, node_str): - if not isinstance(node_str, str): return node_str @@ -812,54 +777,49 @@ def parse_node_ref(self, node_str): node_port_idx = node_str.rfind(':') - if (node_port_idx>0 and node_str[0]=='"' and - node_str[node_port_idx-1]=='"'): - + if (node_port_idx > 0 and node_str[0] == '"' and + node_str[node_port_idx-1] == '"'): return node_str - if node_port_idx>0: - + if node_port_idx > 0: a = node_str[:node_port_idx] b = node_str[node_port_idx+1:] node = quote_if_necessary(a) - - node += ':'+quote_if_necessary(b) + node += ':' + quote_if_necessary(b) return node return node_str - def to_string(self): """Return string representation of edge in DOT language.""" - - src = self.parse_node_ref( self.get_source() ) - dst = self.parse_node_ref( self.get_destination() ) + src = self.parse_node_ref(self.get_source()) + dst = self.parse_node_ref(self.get_destination()) if isinstance(src, frozendict): - edge = [ Subgraph(obj_dict=src).to_string() ] + edge = [Subgraph(obj_dict=src).to_string()] elif isinstance(src, int): - edge = [ str(src) ] + edge = [str(src)] else: - edge = [ src ] + edge = [src] - if (self.get_parent_graph() and + if ( + self.get_parent_graph() and self.get_parent_graph().get_top_graph_type() and - self.get_parent_graph().get_top_graph_type() == 'digraph' ): - - edge.append( '->' ) + self.get_parent_graph().get_top_graph_type() == 'digraph' + ): + edge.append('->') else: - edge.append( '--' ) + edge.append('--') if isinstance(dst, frozendict): - edge.append( Subgraph(obj_dict=dst).to_string() ) + edge.append(Subgraph(obj_dict=dst).to_string()) elif isinstance(dst, int): - edge.append( str(dst) ) + edge.append(str(dst)) else: - edge.append( dst ) - + edge.append(dst) edge_attr = list() @@ -869,21 +829,18 @@ def to_string(self): value = '""' if value is not None: edge_attr.append( - '%s=%s' % (attr, quote_if_necessary(value) ) ) + '%s=%s' % (attr, quote_if_necessary(value))) else: - edge_attr.append( attr ) + edge_attr.append(attr) edge_attr = ', '.join(edge_attr) if edge_attr: - edge.append( ' [' + edge_attr + ']' ) + edge.append(' [' + edge_attr + ']') return ' '.join(edge) + ';' - - - class Graph(Common): """Class representing a graph in Graphviz's dot language. @@ -920,11 +877,9 @@ class Graph(Common): graph_instance.obj_dict['attributes']['fontname'] """ - def __init__(self, graph_name='G', obj_dict=None, graph_type='digraph', strict=False, suppress_disconnected=False, simplify=False, **attrs): - if obj_dict is not None: self.obj_dict = obj_dict @@ -940,7 +895,6 @@ def __init__(self, graph_name='G', obj_dict=None, 'Accepted graph types are: ' 'graph, digraph').format(t=graph_type)) - self.obj_dict['name'] = quote_if_necessary(graph_name) self.obj_dict['type'] = graph_type @@ -955,20 +909,15 @@ def __init__(self, graph_name='G', obj_dict=None, self.set_parent_graph(self) - self.create_attribute_methods(GRAPH_ATTRIBUTES) def __str__(self): return self.to_string() - def get_graph_type(self): - return self.obj_dict['type'] - def get_top_graph_type(self): - parent = self while True: parent_ = parent.get_parent_graph() @@ -978,60 +927,44 @@ def get_top_graph_type(self): return parent.obj_dict['type'] - def set_graph_defaults(self, **attrs): - - self.add_node( Node('graph', **attrs) ) - + self.add_node(Node('graph', **attrs)) def get_graph_defaults(self, **attrs): - graph_nodes = self.get_node('graph') - if isinstance( graph_nodes, (list, tuple)): - return [ node.get_attributes() for node in graph_nodes ] + if isinstance(graph_nodes, (list, tuple)): + return [node.get_attributes() for node in graph_nodes] return graph_nodes.get_attributes() - - def set_node_defaults(self, **attrs): """Define default node attributes. These attributes only apply to nodes added to the graph after calling this method. """ - self.add_node( Node('node', **attrs) ) - + self.add_node(Node('node', **attrs)) def get_node_defaults(self, **attrs): - - graph_nodes = self.get_node('node') - if isinstance( graph_nodes, (list, tuple)): - return [ node.get_attributes() for node in graph_nodes ] + if isinstance(graph_nodes, (list, tuple)): + return [node.get_attributes() for node in graph_nodes] return graph_nodes.get_attributes() - def set_edge_defaults(self, **attrs): - - self.add_node( Node('edge', **attrs) ) - - + self.add_node(Node('edge', **attrs)) def get_edge_defaults(self, **attrs): - graph_nodes = self.get_node('edge') - if isinstance( graph_nodes, (list, tuple)): - return [ node.get_attributes() for node in graph_nodes ] + if isinstance(graph_nodes, (list, tuple)): + return [node.get_attributes() for node in graph_nodes] return graph_nodes.get_attributes() - - def set_simplify(self, simplify): """Set whether to simplify or not. @@ -1039,68 +972,45 @@ def set_simplify(self, simplify): only one edge between two nodes. removing the duplicated ones. """ - self.obj_dict['simplify'] = simplify - - def get_simplify(self): """Get whether to simplify or not. Refer to set_simplify for more information. """ - return self.obj_dict['simplify'] - def set_type(self, graph_type): """Set the graph's type, 'graph' or 'digraph'.""" - self.obj_dict['type'] = graph_type - - def get_type(self): """Get the graph's type, 'graph' or 'digraph'.""" - return self.obj_dict['type'] - - def set_name(self, graph_name): """Set the graph's name.""" - self.obj_dict['name'] = graph_name - - def get_name(self): """Get the graph's name.""" - return self.obj_dict['name'] - - def set_strict(self, val): """Set graph to 'strict' mode. This option is only valid for top level graphs. """ - self.obj_dict['strict'] = val - - def get_strict(self, val): """Get graph's 'strict' mode (True, False). This option is only valid for top level graphs. """ - return self.obj_dict['strict'] - - def set_suppress_disconnected(self, val): """Suppress disconnected nodes in the output graph. @@ -1110,62 +1020,45 @@ def set_suppress_disconnected(self, val): for subgraphs and has effect only in the current graph/subgraph. """ - self.obj_dict['suppress_disconnected'] = val - - def get_suppress_disconnected(self, val): """Get if suppress disconnected is set. Refer to set_suppress_disconnected for more information. """ - return self.obj_dict['suppress_disconnected'] - def get_next_sequence_number(self): - seq = self.obj_dict['current_child_sequence'] - self.obj_dict['current_child_sequence'] += 1 - return seq - - def add_node(self, graph_node): """Adds a node object to the graph. It takes a node object as its only argument and returns None. """ - if not isinstance(graph_node, Node): raise TypeError( 'add_node() received ' + 'a non node class object: ' + str(graph_node)) - node = self.get_node(graph_node.get_name()) if not node: - self.obj_dict['nodes'][graph_node.get_name()] = [ - graph_node.obj_dict ] - - #self.node_dict[graph_node.get_name()] = graph_node.attributes + graph_node.obj_dict + ] graph_node.set_parent_graph(self.get_parent_graph()) - else: - self.obj_dict['nodes'][graph_node.get_name()].append( - graph_node.obj_dict ) + graph_node.obj_dict + ) graph_node.set_sequence(self.get_next_sequence_number()) - - def del_node(self, name, index=None): """Delete a node from the graph. @@ -1183,14 +1076,13 @@ def del_node(self, name, index=None): If nodes are deleted it returns True. If no action is taken it returns False. """ - if isinstance(name, Node): name = name.get_name() if name in self.obj_dict['nodes']: if (index is not None and - index < len(self.obj_dict['nodes'][name])): + index < len(self.obj_dict['nodes'][name])): del self.obj_dict['nodes'][name][index] return True else: @@ -1199,7 +1091,6 @@ def del_node(self, name, index=None): return False - def get_node(self, name): """Retrieve a node from the graph. @@ -1210,7 +1101,6 @@ def get_node(self, name): Node instances is returned. An empty list is returned otherwise. """ - match = list() if name in self.obj_dict['nodes']: @@ -1221,61 +1111,49 @@ def get_node(self, name): return match - def get_nodes(self): """Get the list of Node instances.""" - return self.get_node_list() - def get_node_list(self): """Get the list of Node instances. This method returns the list of Node instances composing the graph. """ - node_objs = list() for node in self.obj_dict['nodes']: - obj_dict_list = self.obj_dict['nodes'][node] - node_objs.extend( [ Node( obj_dict = obj_d ) - for obj_d in obj_dict_list ] ) + obj_dict_list = self.obj_dict['nodes'][node] + node_objs.extend([ + Node(obj_dict=obj_d) + for obj_d in obj_dict_list + ]) return node_objs - - def add_edge(self, graph_edge): """Adds an edge object to the graph. It takes a edge object as its only argument and returns None. """ - if not isinstance(graph_edge, Edge): raise TypeError( 'add_edge() received a non edge class object: ' + str(graph_edge)) - edge_points = ( graph_edge.get_source(), - graph_edge.get_destination() ) + edge_points = (graph_edge.get_source(), + graph_edge.get_destination()) if edge_points in self.obj_dict['edges']: - edge_list = self.obj_dict['edges'][edge_points] edge_list.append(graph_edge.obj_dict) - else: + self.obj_dict['edges'][edge_points] = [graph_edge.obj_dict] - self.obj_dict['edges'][edge_points] = [ graph_edge.obj_dict ] - - - graph_edge.set_sequence( self.get_next_sequence_number() ) - - graph_edge.set_parent_graph( self.get_parent_graph() ) - - + graph_edge.set_sequence(self.get_next_sequence_number()) + graph_edge.set_parent_graph(self.get_parent_graph()) def del_edge(self, src_or_list, dst=None, index=None): """Delete an edge from the graph. @@ -1293,8 +1171,7 @@ def del_edge(self, src_or_list, dst=None, index=None): If edges are deleted it returns True. If no action is taken it returns False. """ - - if isinstance( src_or_list, (list, tuple)): + if isinstance(src_or_list, (list, tuple)): if dst is not None and isinstance(dst, int): index = dst src, dst = src_or_list @@ -1308,9 +1185,8 @@ def del_edge(self, src_or_list, dst=None, index=None): dst = dst.get_name() if (src, dst) in self.obj_dict['edges']: - if (index is not None and - index < len(self.obj_dict['edges'][(src, dst)])): + index < len(self.obj_dict['edges'][(src, dst)])): del self.obj_dict['edges'][(src, dst)][index] return True else: @@ -1319,7 +1195,6 @@ def del_edge(self, src_or_list, dst=None, index=None): return False - def get_edge(self, src_or_list, dst=None): """Retrieved an edge from the graph. @@ -1330,8 +1205,7 @@ def get_edge(self, src_or_list, dst=None): a list of Edge instances is returned. An empty list is returned otherwise. """ - - if isinstance( src_or_list, (list, tuple)) and dst is None: + if isinstance(src_or_list, (list, tuple)) and dst is None: edge_points = tuple(src_or_list) edge_points_reverse = (edge_points[1], edge_points[0]) else: @@ -1342,11 +1216,11 @@ def get_edge(self, src_or_list, dst=None): if edge_points in self.obj_dict['edges'] or ( self.get_top_graph_type() == 'graph' and - edge_points_reverse in self.obj_dict['edges']): - + edge_points_reverse in self.obj_dict['edges'] + ): edges_obj_dict = self.obj_dict['edges'].get( edge_points, - self.obj_dict['edges'].get( edge_points_reverse, None )) + self.obj_dict['edges'].get(edge_points_reverse, None)) for edge_obj_dict in edges_obj_dict: match.append( @@ -1356,58 +1230,49 @@ def get_edge(self, src_or_list, dst=None): return match - def get_edges(self): return self.get_edge_list() - def get_edge_list(self): """Get the list of Edge instances. This method returns the list of Edge instances composing the graph. """ - edge_objs = list() for edge in self.obj_dict['edges']: - obj_dict_list = self.obj_dict['edges'][edge] - edge_objs.extend( - [Edge(obj_dict=obj_d) - for obj_d in obj_dict_list]) + obj_dict_list = self.obj_dict['edges'][edge] + edge_objs.extend([ + Edge(obj_dict=obj_d) + for obj_d in obj_dict_list + ]) return edge_objs - - def add_subgraph(self, sgraph): """Adds an subgraph object to the graph. It takes a subgraph object as its only argument and returns None. """ - if (not isinstance(sgraph, Subgraph) and - not isinstance(sgraph, Cluster)): + not isinstance(sgraph, Cluster)): raise TypeError( 'add_subgraph() received a non subgraph class object:' + str(sgraph)) if sgraph.get_name() in self.obj_dict['subgraphs']: - sgraph_list = self.obj_dict['subgraphs'][ sgraph.get_name() ] - sgraph_list.append( sgraph.obj_dict ) + sgraph_list = self.obj_dict['subgraphs'][sgraph.get_name()] + sgraph_list.append(sgraph.obj_dict) else: self.obj_dict['subgraphs'][sgraph.get_name()] = [ sgraph.obj_dict] - sgraph.set_sequence( self.get_next_sequence_number() ) - - sgraph.set_parent_graph( self.get_parent_graph() ) - - - + sgraph.set_sequence(self.get_next_sequence_number()) + sgraph.set_parent_graph(self.get_parent_graph()) def get_subgraph(self, name): """Retrieved a subgraph from the graph. @@ -1419,47 +1284,38 @@ def get_subgraph(self, name): Subgraph instances is returned. An empty list is returned otherwise. """ - match = list() if name in self.obj_dict['subgraphs']: - sgraphs_obj_dict = self.obj_dict['subgraphs'].get( name ) + sgraphs_obj_dict = self.obj_dict['subgraphs'].get(name) for obj_dict_list in sgraphs_obj_dict: - #match.extend( Subgraph( obj_dict = obj_d ) - # for obj_d in obj_dict_list ) - match.append( Subgraph( obj_dict = obj_dict_list ) ) + match.append(Subgraph(obj_dict=obj_dict_list)) return match - def get_subgraphs(self): - return self.get_subgraph_list() - def get_subgraph_list(self): """Get the list of Subgraph instances. This method returns the list of Subgraph instances in the graph. """ - sgraph_objs = list() for sgraph in self.obj_dict['subgraphs']: - obj_dict_list = self.obj_dict['subgraphs'][sgraph] - sgraph_objs.extend( - [Subgraph(obj_dict=obj_d) - for obj_d in obj_dict_list]) + obj_dict_list = self.obj_dict['subgraphs'][sgraph] + sgraph_objs.extend([ + Subgraph(obj_dict=obj_d) + for obj_d in obj_dict_list + ]) return sgraph_objs - - def set_parent_graph(self, parent_graph): - self.obj_dict['parent_graph'] = parent_graph for k in self.obj_dict['nodes']: @@ -1477,16 +1333,12 @@ def set_parent_graph(self, parent_graph): for obj in obj_list: Graph(obj_dict=obj).set_parent_graph(parent_graph) - - def to_string(self): """Return string representation of graph in DOT language. @return: graph and subelements @rtype: `str` """ - - graph = list() if self.obj_dict.get('strict', None) is not None: @@ -1516,10 +1368,9 @@ def to_string(self): graph.append('%s=%s' % (attr, quote_if_necessary(val))) else: - graph.append( attr ) - - graph.append( ';\n' ) + graph.append(attr) + graph.append(';\n') edges_done = set() @@ -1542,52 +1393,45 @@ def to_string(self): for k in self.obj_dict['subgraphs']: sgraph_obj_dicts.extend(self.obj_dict['subgraphs'][k]) - - obj_list = [(obj['sequence'], obj) - for obj in (edge_obj_dicts + - node_obj_dicts + sgraph_obj_dicts) ] + obj_list = [ + (obj['sequence'], obj) + for obj in (edge_obj_dicts + node_obj_dicts + sgraph_obj_dicts) + ] obj_list.sort(key=lambda x: x[0]) for idx, obj in obj_list: if obj['type'] == 'node': - node = Node(obj_dict=obj) if self.obj_dict.get('suppress_disconnected', False): if (node.get_name() not in edge_src_set and - node.get_name() not in edge_dst_set): - + node.get_name() not in edge_dst_set): continue - graph.append( node.to_string()+'\n' ) + graph.append(node.to_string() + '\n') elif obj['type'] == 'edge': - edge = Edge(obj_dict=obj) if (self.obj_dict.get('simplify', False) and edge in edges_done): continue - graph.append( edge.to_string() + '\n' ) + graph.append(edge.to_string() + '\n') edges_done.add(edge) else: - sgraph = Subgraph(obj_dict=obj) + graph.append(sgraph.to_string()+'\n') - graph.append( sgraph.to_string()+'\n' ) - - graph.append( '}\n' ) + graph.append('}\n') return ''.join(graph) - class Subgraph(Graph): - """Class representing a subgraph in Graphviz's dot language. This class implements the methods to work on a representation @@ -1618,7 +1462,6 @@ class Subgraph(Graph): subgraph_instance.obj_dict['attributes']['fontname'] """ - # RMF: subgraph should have all the # attributes of graph so it can be passed # as a graph to all methods @@ -1626,8 +1469,6 @@ class Subgraph(Graph): def __init__(self, graph_name='', obj_dict=None, suppress_disconnected=False, simplify=False, **attrs): - - Graph.__init__( self, graph_name=graph_name, obj_dict=obj_dict, suppress_disconnected=suppress_disconnected, @@ -1638,10 +1479,7 @@ def __init__(self, graph_name='', self.obj_dict['type'] = 'subgraph' - - class Cluster(Graph): - """Class representing a cluster in Graphviz's dot language. This class implements the methods to work on a representation @@ -1673,11 +1511,9 @@ class Cluster(Graph): cluster_instance.obj_dict['attributes']['fontname'] """ - def __init__(self, graph_name='subG', obj_dict=None, suppress_disconnected=False, simplify=False, **attrs): - Graph.__init__( self, graph_name=graph_name, obj_dict=obj_dict, suppress_disconnected=suppress_disconnected, @@ -1691,10 +1527,6 @@ def __init__(self, graph_name='subG', self.create_attribute_methods(CLUSTER_ATTRIBUTES) - - - - class Dot(Graph): """A container for handling a dot language file. @@ -1703,8 +1535,6 @@ class Dot(Graph): the base class 'Graph'. """ - - def __init__(self, *argsl, **argsd): Graph.__init__(self, *argsl, **argsd) @@ -1747,16 +1577,12 @@ def new_method( self.__setattr__(name, new_method) def __getstate__(self): - dict = copy.copy(self.obj_dict) - return dict def __setstate__(self, state): - self.obj_dict = state - def set_shape_files(self, file_paths): """Add the paths of the required image files. @@ -1774,13 +1600,11 @@ def set_shape_files(self, file_paths): the same temporary location where the graph is going to be rendered. """ + if isinstance(file_paths, str_type): + self.shape_files.append(file_paths) - if isinstance( file_paths, str_type): - self.shape_files.append( file_paths ) - - if isinstance( file_paths, (list, tuple) ): - self.shape_files.extend( file_paths ) - + if isinstance(file_paths, (list, tuple)): + self.shape_files.extend(file_paths) def set_prog(self, prog): """Sets the default program. @@ -1790,7 +1614,6 @@ def set_prog(self, prog): """ self.prog = prog - def write(self, path, prog=None, format='raw', encoding=None): """Writes a graph to a file. @@ -1888,7 +1711,6 @@ def create(self, prog=None, format='ps', encoding=None): then you may want to give the absolute path to the executable (for example, to `dot.exe`) in `prog`. """ - if prog is None: prog = self.prog diff --git a/test/pydot_unittest.py b/test/pydot_unittest.py index c2accef..4df26f8 100644 --- a/test/pydot_unittest.py +++ b/test/pydot_unittest.py @@ -12,7 +12,6 @@ import os import pickle import string -import subprocess import sys import warnings @@ -29,42 +28,29 @@ class TestGraphAPI(unittest.TestCase): def setUp(self): - 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): - g = pydot.Dot() g.set_type('digraph') node = pydot.Node('legend') @@ -76,22 +62,19 @@ def test_create_simple_graph_with_node(self): assert s == expected def test_attribute_with_implicit_value(self): - - d='digraph {\na -> b[label="hi", decorate];\n}' + d = 'digraph {\na -> b[label="hi", decorate];\n}' graphs = pydot.graph_from_dot_data(d) (g,) = graphs 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) @@ -100,43 +83,39 @@ def test_subgraphs(self): self.assertEqual(g.get_subgraph_list()[0].get_name(), s.get_name()) - def test_graph_pickling(self): - - 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!' ) ) + 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!')) pickle.dumps(g) def test_unicode_ids(self): - node1 = '"aánñoöüé€"' node2 = '"îôø®çßΩ"' 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) graphs = pydot.graph_from_dot_data(g.to_string()) (g2,) = graphs - self.assertEqual( g2.get_node(node1)[0].get_name(), node1 ) - self.assertEqual( g2.get_node(node2)[0].get_name(), 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 ) + self.assertEqual(g2.get_edges()[0].get_source(), node1) + self.assertEqual(g2.get_edges()[0].get_destination(), node2) def test_graph_simplify(self): # Fail example: pydot 1.0.2. GH pydot/pydot#92 OP patch 1. @@ -178,28 +157,26 @@ def test_graph_with_shapefiles(self): return 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')] + os.path.join(shapefile_dir, fname) + for fname in os.listdir(shapefile_dir) + if fname.endswith('.png') + ] f = open(dot_file, 'rt') graph_data = f.read() f.close() - #g = dot_parser.parse_dot_data(graph_data) graphs = pydot.graph_from_dot_data(graph_data) (g,) = graphs - 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, encoding='ascii') - 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}' @@ -219,7 +196,6 @@ def _render_with_graphviz(self, filename, encoding): ) assert process.returncode == 0, stderr_data - return sha256(stdout_data).hexdigest() def _render_with_pydot(self, filename, encoding): @@ -234,12 +210,10 @@ def test_my_regression_tests(self): path = os.path.join(test_dir, TESTS_DIR_1) self._render_and_compare_dot_files(path) - def test_graphviz_regression_tests(self): path = os.path.join(test_dir, TESTS_DIR_2) self._render_and_compare_dot_files(path) - def _render_and_compare_dot_files(self, directory): # files that confuse `chardet` encodings = { @@ -260,115 +234,80 @@ def _render_and_compare_dot_files(self, directory): assert pydot_sha == graphviz_sha, (pydot_sha, graphviz_sha) 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.graph_directed.add_node(pydot.Node('"node"')) self.assertEqual( - self.graph_directed.get_nodes()[0].get_name(), '"node"') - + 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.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.graph_directed.add_node(pydot.Node('node')) self.assertEqual( - self.graph_directed.get_nodes()[0].get_name(), 'node') - + 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.graph_directed.add_node(pydot.Node('node')) self.assertEqual( - self.graph_directed.get_nodes()[0].to_string() , '' ) - + 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.graph_directed.add_node(pydot.Node('node', shape='box')) self.assertEqual( self.graph_directed.get_nodes()[0].to_string(), - 'node [shape=box];') - + 'node [shape=box];' + ) def test_names_of_a_thousand_nodes(self): - self._reset_graphs() - - names = { 'node_%05d' % i for i in range(10**3) } - + names = {'node_%05d' % i for i in range(10**3)} for name in names: - - self.graph_directed.add_node( pydot.Node(name, label=name) ) + self.graph_directed.add_node(pydot.Node(name, label=name)) self.assertEqual( - {n.get_name() - for n in self.graph_directed.get_nodes()}, names) - + {n.get_name() for n in self.graph_directed.get_nodes()}, names + ) def test_executable_not_found_exception(self): graph = pydot.Dot('graphname', graph_type='digraph') self.assertRaises(Exception, graph.create, prog='dothehe') - 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): 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) def test_dot_args(self): g = pydot.Dot() @@ -393,25 +332,29 @@ def test_edge_point_namestr(self): def test_edge_point_object_node(self): self._reset_graphs() - self.graph_directed.add_edge(pydot.Edge(pydot.Node('a'), - pydot.Node('b'))) + self.graph_directed.add_edge( + pydot.Edge(pydot.Node('a'), pydot.Node('b')) + ) self.assertEqual( self.graph_directed.get_edges()[0].to_string(), 'a -> b;') def test_edge_point_object_subgraph(self): self._reset_graphs() - self.graph_directed.add_edge(pydot.Edge(pydot.Subgraph('a'), - pydot.Subgraph('b'))) + self.graph_directed.add_edge( + pydot.Edge(pydot.Subgraph('a'), pydot.Subgraph('b')) + ) self.assertEqual( self.graph_directed.get_edges()[0].to_string(), 'a -> b;') def test_edge_point_object_cluster(self): self._reset_graphs() - self.graph_directed.add_edge(pydot.Edge(pydot.Cluster('a'), - pydot.Cluster('b'))) + self.graph_directed.add_edge( + pydot.Edge(pydot.Cluster('a'), pydot.Cluster('b')) + ) self.assertEqual( self.graph_directed.get_edges()[0].to_string(), - 'cluster_a -> cluster_b;') + 'cluster_a -> cluster_b;' + ) def test_graph_from_adjacency_matrix(self): g = pydot.graph_from_adjacency_matrix(