Fix flakes8 and improve readability
This commit is contained in:
parent
6b816be37c
commit
d7c49b1389
|
@ -1,25 +1,17 @@
|
|||
# -*- coding: Latin-1 -*-
|
||||
"""Graphviz's dot language Python interface.
|
||||
|
||||
This module provides with a full interface to create handle modify
|
||||
and process graphs in Graphviz's dot language.
|
||||
|
||||
References:
|
||||
|
||||
pydot Homepage: http://code.google.com/p/pydot/
|
||||
Graphviz: http://www.graphviz.org/
|
||||
DOT Language: http://www.graphviz.org/doc/info/lang.html
|
||||
|
||||
Copyright (c) 2005-2011 Ero Carrera <ero.carrera@gmail.com>
|
||||
|
||||
Distributed under MIT license [http://opensource.org/licenses/mit-license.html].
|
||||
"""
|
||||
# Graphviz's dot language Python interface.
|
||||
# This module provides with a full interface to create handle modify
|
||||
# and process graphs in Graphviz's dot language.
|
||||
# References:
|
||||
# pydot Homepage: http://code.google.com/p/pydot/
|
||||
# Graphviz: http://www.graphviz.org/
|
||||
# DOT Language: http://www.graphviz.org/doc/info/lang.html
|
||||
# Copyright (c) 2005-2011 Ero Carrera <ero.carrera@gmail.com>
|
||||
# Distributed under MIT license
|
||||
# [http://opensource.org/licenses/mit-license.html].
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
__author__ = 'Ero Carrera'
|
||||
__license__ = 'MIT'
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
@ -32,8 +24,11 @@ from operator import itemgetter
|
|||
try:
|
||||
from . import _dotparser as dot_parser
|
||||
except Exception:
|
||||
print("Couldn't import _dotparser, loading of dot files will not be possible.")
|
||||
print("Couldn't import _dotparser, "
|
||||
"loading of dot files will not be possible.")
|
||||
|
||||
__author__ = 'Ero Carrera'
|
||||
__license__ = 'MIT'
|
||||
|
||||
PY3 = not sys.version_info < (3, 0, 0)
|
||||
|
||||
|
@ -103,23 +98,25 @@ CLUSTER_ATTRIBUTES = set([
|
|||
])
|
||||
|
||||
|
||||
def is_string_like(obj): # from John Hunter, types-free version
|
||||
"""Check if obj is string."""
|
||||
def is_string_like(obj):
|
||||
"""Check if obj is string.
|
||||
from John Hunter, types-free version"""
|
||||
try:
|
||||
obj + ''
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_fobj(fname, mode='w+'):
|
||||
"""Obtain a proper file object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : string, file object, file descriptor
|
||||
If a string or file descriptor, then we create a file object. If *fname*
|
||||
is a file object, then we do nothing and ignore the specified *mode*
|
||||
parameter.
|
||||
If a string or file descriptor, then we create a file object. If
|
||||
*fname* is a file object, then we do nothing and ignore the specified
|
||||
*mode* parameter.
|
||||
mode : str
|
||||
The mode of the file to be opened.
|
||||
|
||||
|
@ -129,9 +126,10 @@ def get_fobj(fname, mode='w+'):
|
|||
The file object.
|
||||
close : bool
|
||||
If *fname* was a string, then *close* will be *True* to signify that
|
||||
the file object should be closed after writing to it. Otherwise, *close*
|
||||
will be *False* signifying that the user, in essence, created the file
|
||||
object already and that subsequent operations should not close it.
|
||||
the file object should be closed after writing to it. Otherwise,
|
||||
*close* will be *False* signifying that the user, in essence,
|
||||
created the file object already and that subsequent operations
|
||||
should not close it.
|
||||
|
||||
"""
|
||||
if is_string_like(fname):
|
||||
|
@ -431,7 +429,8 @@ def __find_executables(path):
|
|||
"""
|
||||
|
||||
success = False
|
||||
progs = {'dot': '', 'twopi': '', 'neato': '', 'circo': '', 'fdp': '', 'sfdp': ''}
|
||||
progs = {'dot': '', 'twopi': '', 'neato': '', 'circo': '', 'fdp': '',
|
||||
'sfdp': ''}
|
||||
|
||||
was_quoted = False
|
||||
path = path.strip()
|
||||
|
@ -515,7 +514,8 @@ def find_graphviz():
|
|||
|
||||
def RegOpenKeyEx(key, subkey, opt, sam):
|
||||
result = ctypes.c_uint(0)
|
||||
ctypes.windll.advapi32.RegOpenKeyExA(key, subkey, opt, sam, ctypes.byref(result))
|
||||
ctypes.windll.advapi32.RegOpenKeyExA(key, subkey, opt, sam,
|
||||
ctypes.byref(result))
|
||||
return result.value
|
||||
|
||||
def RegQueryValueEx(hkey, valuename):
|
||||
|
@ -556,8 +556,9 @@ def find_graphviz():
|
|||
path = RegQueryValueEx(hkey, "InstallPath")
|
||||
RegCloseKey(hkey)
|
||||
|
||||
# The regitry variable might exist, left by old installations
|
||||
# but with no value, in those cases we keep searching...
|
||||
# The regitry variable might exist, left by
|
||||
# old installations but with no value, in those cases
|
||||
# we keep searching...
|
||||
if not path:
|
||||
continue
|
||||
|
||||
|
@ -565,11 +566,9 @@ def find_graphviz():
|
|||
path = os.path.join(path, "bin")
|
||||
progs = __find_executables(path)
|
||||
if progs is not None:
|
||||
#print("Used Windows registry")
|
||||
return progs
|
||||
|
||||
except Exception:
|
||||
#raise
|
||||
pass
|
||||
else:
|
||||
break
|
||||
|
@ -579,7 +578,6 @@ def find_graphviz():
|
|||
for path in os.environ['PATH'].split(os.pathsep):
|
||||
progs = __find_executables(path)
|
||||
if progs is not None:
|
||||
#print("Used path")
|
||||
return progs
|
||||
|
||||
# Method 3 (Windows only)
|
||||
|
@ -590,16 +588,15 @@ def find_graphviz():
|
|||
if 'PROGRAMFILES' in os.environ:
|
||||
# Note, we could also use the win32api to get this
|
||||
# information, but win32api may not be installed.
|
||||
path = os.path.join(os.environ['PROGRAMFILES'], 'ATT', 'GraphViz', 'bin')
|
||||
path = os.path.join(os.environ['PROGRAMFILES'], 'ATT',
|
||||
'GraphViz', 'bin')
|
||||
else:
|
||||
#Just in case, try the default...
|
||||
# Just in case, try the default...
|
||||
path = r"C:\Program Files\att\Graphviz\bin"
|
||||
|
||||
progs = __find_executables(path)
|
||||
|
||||
if progs is not None:
|
||||
|
||||
#print("Used default install location")
|
||||
return progs
|
||||
|
||||
for path in (
|
||||
|
@ -611,7 +608,6 @@ def find_graphviz():
|
|||
|
||||
progs = __find_executables(path)
|
||||
if progs is not None:
|
||||
#print("Used path")
|
||||
return progs
|
||||
|
||||
# Failed to find GraphViz
|
||||
|
@ -626,23 +622,18 @@ class Common(object):
|
|||
"""
|
||||
|
||||
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
|
||||
|
||||
default_node_name = self.obj_dict['type']
|
||||
|
||||
# The defaults for graphs are set on a node named 'graph'
|
||||
|
@ -676,11 +667,9 @@ class Common(object):
|
|||
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):
|
||||
|
@ -693,7 +682,6 @@ class Common(object):
|
|||
|
||||
which are defined for all the existing attributes.
|
||||
"""
|
||||
|
||||
self.obj_dict['attributes'][name] = value
|
||||
|
||||
def get(self, name):
|
||||
|
@ -706,37 +694,28 @@ class Common(object):
|
|||
|
||||
which are defined for all the existing attributes.
|
||||
"""
|
||||
|
||||
return self.obj_dict['attributes'].get(name, None)
|
||||
|
||||
def get_attributes(self):
|
||||
""""""
|
||||
|
||||
return self.obj_dict['attributes']
|
||||
|
||||
def set_sequence(self, seq):
|
||||
|
||||
self.obj_dict['sequence'] = seq
|
||||
|
||||
def get_sequence(self):
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
# Generate all the Getter methods.
|
||||
#
|
||||
self.__setattr__('get_' + attr, lambda a=attr: self.__get_attribute__(a))
|
||||
self.__setattr__('get_' + attr,
|
||||
lambda a=attr: self.__get_attribute__(a))
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
|
@ -750,7 +729,8 @@ class Error(Exception):
|
|||
|
||||
|
||||
class InvocationException(Exception):
|
||||
"""To indicate that a ploblem occurred while running any of the GraphViz executables.
|
||||
"""To indicate that a ploblem occurred while running any of the
|
||||
GraphViz executables.
|
||||
"""
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
@ -773,11 +753,9 @@ class Node(Common):
|
|||
"""
|
||||
|
||||
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
|
||||
#
|
||||
# for any GraphViz object are dealt with as if they were
|
||||
# Node definitions
|
||||
|
||||
if obj_dict is not None:
|
||||
self.obj_dict = obj_dict
|
||||
|
@ -785,7 +763,6 @@ class Node(Common):
|
|||
self.obj_dict = dict()
|
||||
|
||||
# Copy the attributes
|
||||
#
|
||||
self.obj_dict['attributes'] = dict(attrs)
|
||||
self.obj_dict['type'] = 'node'
|
||||
self.obj_dict['parent_graph'] = None
|
||||
|
@ -793,7 +770,6 @@ class Node(Common):
|
|||
self.obj_dict['sequence'] = None
|
||||
|
||||
# Remove the compass point
|
||||
#
|
||||
port = None
|
||||
if isinstance(name, basestring) and not name.startswith('"'):
|
||||
idx = name.find(':')
|
||||
|
@ -810,17 +786,14 @@ class Node(Common):
|
|||
|
||||
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):
|
||||
|
@ -837,14 +810,13 @@ class Node(Common):
|
|||
def to_string(self):
|
||||
"""Returns a string representation of the node in dot language.
|
||||
"""
|
||||
|
||||
# RMF: special case defaults for node, edge and graph properties.
|
||||
#
|
||||
node = quote_if_necessary(self.obj_dict['name'])
|
||||
|
||||
node_attr = list()
|
||||
|
||||
for attr, value in sorted(self.obj_dict['attributes'].items(), key=itemgetter(0)):
|
||||
for attr, value in sorted(self.obj_dict['attributes'].items(),
|
||||
key=itemgetter(0)):
|
||||
if value is not None:
|
||||
node_attr.append('%s=%s' % (attr, quote_if_necessary(value)))
|
||||
else:
|
||||
|
@ -891,20 +863,15 @@ class Edge(Common):
|
|||
"""
|
||||
|
||||
def __init__(self, src='', dst='', obj_dict=None, **attrs):
|
||||
|
||||
if isinstance(src, (list, tuple)) and dst == '':
|
||||
src, dst = src
|
||||
|
||||
if obj_dict is not None:
|
||||
|
||||
self.obj_dict = obj_dict
|
||||
|
||||
else:
|
||||
|
||||
self.obj_dict = dict()
|
||||
|
||||
# Copy the attributes
|
||||
#
|
||||
self.obj_dict['attributes'] = dict(attrs)
|
||||
self.obj_dict['type'] = 'edge'
|
||||
self.obj_dict['parent_graph'] = None
|
||||
|
@ -925,12 +892,10 @@ class Edge(Common):
|
|||
|
||||
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):
|
||||
|
@ -954,7 +919,6 @@ class Edge(Common):
|
|||
|
||||
# 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
|
||||
|
@ -965,11 +929,9 @@ class Edge(Common):
|
|||
if (self.get_source() == edge.get_source() and
|
||||
self.get_destination() == edge.get_destination()):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def parse_node_ref(self, node_str):
|
||||
|
||||
if not isinstance(node_str, str):
|
||||
return node_str
|
||||
|
||||
|
@ -985,11 +947,8 @@ class Edge(Common):
|
|||
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)
|
||||
|
||||
return node
|
||||
|
||||
return node_str
|
||||
|
@ -997,7 +956,6 @@ class Edge(Common):
|
|||
def to_string(self):
|
||||
"""Returns a string representation of the edge in dot language.
|
||||
"""
|
||||
|
||||
src = self.parse_node_ref(self.get_source())
|
||||
dst = self.parse_node_ref(self.get_destination())
|
||||
|
||||
|
@ -1026,7 +984,8 @@ class Edge(Common):
|
|||
|
||||
edge_attr = list()
|
||||
|
||||
for attr, value in sorted(self.obj_dict['attributes'].items(), key=itemgetter(0)):
|
||||
for attr, value in sorted(self.obj_dict['attributes'].items(),
|
||||
key=itemgetter(0)):
|
||||
if value is not None:
|
||||
edge_attr.append('%s=%s' % (attr, quote_if_necessary(value)))
|
||||
else:
|
||||
|
@ -1077,8 +1036,9 @@ class Graph(Common):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, graph_name='G', obj_dict=None, graph_type='digraph', strict=False,
|
||||
suppress_disconnected=False, simplify=False, **attrs):
|
||||
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
|
||||
|
@ -1163,7 +1123,6 @@ class Graph(Common):
|
|||
only one edge between two nodes. removing the
|
||||
duplicated ones.
|
||||
"""
|
||||
|
||||
self.obj_dict['simplify'] = simplify
|
||||
|
||||
def get_simplify(self):
|
||||
|
@ -1171,27 +1130,22 @@ class Graph(Common):
|
|||
|
||||
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):
|
||||
|
@ -1199,7 +1153,6 @@ class Graph(Common):
|
|||
|
||||
This option is only valid for top level graphs.
|
||||
"""
|
||||
|
||||
self.obj_dict['strict'] = val
|
||||
|
||||
def get_strict(self, val):
|
||||
|
@ -1207,7 +1160,6 @@ class Graph(Common):
|
|||
|
||||
This option is only valid for top level graphs.
|
||||
"""
|
||||
|
||||
return self.obj_dict['strict']
|
||||
|
||||
def set_suppress_disconnected(self, val):
|
||||
|
@ -1217,7 +1169,6 @@ class Graph(Common):
|
|||
edges. This option works also for subgraphs and has effect only in the
|
||||
current graph/subgraph.
|
||||
"""
|
||||
|
||||
self.obj_dict['suppress_disconnected'] = val
|
||||
|
||||
def get_suppress_disconnected(self, val):
|
||||
|
@ -1225,7 +1176,6 @@ class Graph(Common):
|
|||
|
||||
Refer to set_suppress_disconnected for more information.
|
||||
"""
|
||||
|
||||
return self.obj_dict['suppress_disconnected']
|
||||
|
||||
def get_next_sequence_number(self):
|
||||
|
@ -1239,19 +1189,21 @@ class Graph(Common):
|
|||
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))
|
||||
raise TypeError(''.join([
|
||||
'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.obj_dict['nodes'][graph_node.get_name()] =\
|
||||
[graph_node.obj_dict]
|
||||
|
||||
#self.node_dict[graph_node.get_name()] = graph_node.attributes
|
||||
graph_node.set_parent_graph(self.get_parent_graph())
|
||||
else:
|
||||
self.obj_dict['nodes'][graph_node.get_name()].append(graph_node.obj_dict)
|
||||
self.obj_dict['nodes'][graph_node.get_name()].\
|
||||
append(graph_node.obj_dict)
|
||||
|
||||
graph_node.set_sequence(self.get_next_sequence_number())
|
||||
|
||||
|
@ -1296,7 +1248,6 @@ class Graph(Common):
|
|||
Node instances is returned.
|
||||
An empty list is returned otherwise.
|
||||
"""
|
||||
|
||||
match = list()
|
||||
|
||||
if name in self.obj_dict['nodes']:
|
||||
|
@ -1310,7 +1261,6 @@ class Graph(Common):
|
|||
|
||||
def get_nodes(self):
|
||||
"""Get the list of Node instances."""
|
||||
|
||||
return self.get_node_list()
|
||||
|
||||
def get_node_list(self):
|
||||
|
@ -1319,7 +1269,6 @@ class Graph(Common):
|
|||
This method returns the list of Node instances
|
||||
composing the graph.
|
||||
"""
|
||||
|
||||
node_objs = list()
|
||||
|
||||
for node, obj_dict_list in self.obj_dict['nodes'].items():
|
||||
|
@ -1334,12 +1283,11 @@ class Graph(Common):
|
|||
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.
|
||||
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))
|
||||
raise TypeError(''.join(['add_edge() received a non edge class '
|
||||
'object: ', str(graph_edge)]))
|
||||
|
||||
edge_points = (graph_edge.get_source(), graph_edge.get_destination())
|
||||
|
||||
|
@ -1384,7 +1332,8 @@ class Graph(Common):
|
|||
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)]):
|
||||
if (index is not None and index <
|
||||
len(self.obj_dict['edges'][(src, dst)])):
|
||||
del self.obj_dict['edges'][(src, dst)][index]
|
||||
return True
|
||||
else:
|
||||
|
@ -1424,8 +1373,8 @@ class Graph(Common):
|
|||
|
||||
for edge_obj_dict in edges_obj_dict:
|
||||
match.append(
|
||||
Edge(edge_points[0], edge_points[1], obj_dict=edge_obj_dict)
|
||||
)
|
||||
Edge(edge_points[0], edge_points[1],
|
||||
obj_dict=edge_obj_dict))
|
||||
|
||||
return match
|
||||
|
||||
|
@ -1438,7 +1387,6 @@ class Graph(Common):
|
|||
This method returns the list of Edge instances
|
||||
composing the graph.
|
||||
"""
|
||||
|
||||
edge_objs = list()
|
||||
|
||||
for edge, obj_dict_list in self.obj_dict['edges'].items():
|
||||
|
@ -1457,8 +1405,11 @@ class Graph(Common):
|
|||
None.
|
||||
"""
|
||||
|
||||
if not isinstance(sgraph, Subgraph) and not isinstance(sgraph, Cluster):
|
||||
raise TypeError('add_subgraph() received a non subgraph class object:' + str(sgraph))
|
||||
if (not isinstance(sgraph, Subgraph) and
|
||||
not isinstance(sgraph, Cluster)):
|
||||
raise TypeError(''.join([
|
||||
'add_subgraph() received a non subgraph class object:',
|
||||
str(sgraph)]))
|
||||
|
||||
if sgraph.get_name() in self.obj_dict['subgraphs']:
|
||||
|
||||
|
@ -1489,7 +1440,6 @@ class Graph(Common):
|
|||
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))
|
||||
|
||||
return match
|
||||
|
@ -1516,7 +1466,6 @@ class Graph(Common):
|
|||
return sgraph_objs
|
||||
|
||||
def set_parent_graph(self, parent_graph):
|
||||
|
||||
self.obj_dict['parent_graph'] = parent_graph
|
||||
|
||||
for obj_list in self.obj_dict['nodes'].values():
|
||||
|
@ -1544,14 +1493,17 @@ class Graph(Common):
|
|||
graph.append('strict ')
|
||||
|
||||
if self.obj_dict['name'] == '':
|
||||
if 'show_keyword' in self.obj_dict and self.obj_dict['show_keyword']:
|
||||
if ('show_keyword' in self.obj_dict and
|
||||
self.obj_dict['show_keyword']):
|
||||
graph.append('subgraph {\n')
|
||||
else:
|
||||
graph.append('{\n')
|
||||
else:
|
||||
graph.append('%s %s {\n' % (self.obj_dict['type'], self.obj_dict['name']))
|
||||
graph.append('%s %s {\n' % (self.obj_dict['type'],
|
||||
self.obj_dict['name']))
|
||||
|
||||
for attr, value in sorted(self.obj_dict['attributes'].items(), key=itemgetter(0)):
|
||||
for attr, value in sorted(self.obj_dict['attributes'].items(),
|
||||
key=itemgetter(0)):
|
||||
if value is not None:
|
||||
graph.append('%s=%s' % (attr, quote_if_necessary(value)))
|
||||
else:
|
||||
|
@ -1566,7 +1518,8 @@ class Graph(Common):
|
|||
edge_obj_dicts.extend(e)
|
||||
|
||||
if edge_obj_dicts:
|
||||
edge_src_set, edge_dst_set = list(zip(*[obj['points'] for obj in edge_obj_dicts]))
|
||||
edge_src_set, edge_dst_set = list(
|
||||
zip(*[obj['points'] for obj in edge_obj_dicts]))
|
||||
edge_src_set, edge_dst_set = set(edge_src_set), set(edge_dst_set)
|
||||
else:
|
||||
edge_src_set, edge_dst_set = set(), set()
|
||||
|
@ -1620,7 +1573,8 @@ class Subgraph(Graph):
|
|||
This class implements the methods to work on a representation
|
||||
of a subgraph in Graphviz's dot language.
|
||||
|
||||
subgraph(graph_name='subG', suppress_disconnected=False, attribute=value, ...)
|
||||
subgraph(graph_name='subG', suppress_disconnected=False, attribute=value,
|
||||
...)
|
||||
|
||||
graph_name:
|
||||
the subgraph's name
|
||||
|
@ -1641,17 +1595,17 @@ class Subgraph(Graph):
|
|||
subgraph_instance.obj_dict['attributes']['label']
|
||||
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
|
||||
#
|
||||
|
||||
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, simplify=simplify, **attrs)
|
||||
suppress_disconnected=suppress_disconnected, simplify=simplify,
|
||||
**attrs)
|
||||
|
||||
if obj_dict is None:
|
||||
self.obj_dict['type'] = 'subgraph'
|
||||
|
@ -1664,7 +1618,8 @@ class Cluster(Graph):
|
|||
This class implements the methods to work on a representation
|
||||
of a cluster in Graphviz's dot language.
|
||||
|
||||
cluster(graph_name='subG', suppress_disconnected=False, attribute=value, ...)
|
||||
cluster(graph_name='subG', suppress_disconnected=False, attribute=value,
|
||||
...)
|
||||
|
||||
graph_name:
|
||||
the cluster's name (the string 'cluster' will be always prepended)
|
||||
|
@ -1686,14 +1641,12 @@ class Cluster(Graph):
|
|||
cluster_instance.obj_dict['attributes']['fontname']
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, graph_name='subG', obj_dict=None, suppress_disconnected=False,
|
||||
simplify=False, **attrs):
|
||||
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, simplify=simplify, **attrs
|
||||
)
|
||||
Graph.__init__(self, graph_name=graph_name, obj_dict=obj_dict,
|
||||
suppress_disconnected=suppress_disconnected,
|
||||
simplify=simplify, **attrs)
|
||||
|
||||
if obj_dict is None:
|
||||
self.obj_dict['type'] = 'subgraph'
|
||||
|
@ -1740,7 +1693,8 @@ class Dot(Graph):
|
|||
for frmt in self.formats + ['raw']:
|
||||
self.__setattr__(
|
||||
'write_' + frmt,
|
||||
lambda path, f=frmt, prog=self.prog: self.write(path, format=f, prog=prog)
|
||||
lambda path, f=frmt, prog=self.prog: self.write(path, format=f,
|
||||
prog=prog)
|
||||
)
|
||||
|
||||
f = self.__dict__['write_' + frmt]
|
||||
|
@ -1759,13 +1713,13 @@ class Dot(Graph):
|
|||
"""Add the paths of the required image files.
|
||||
|
||||
If the graph needs graphic objects to be used as shapes or otherwise
|
||||
those need to be in the same folder as the graph is going to be rendered
|
||||
from. Alternatively the absolute path to the files can be specified when
|
||||
including the graphics in the graph.
|
||||
those need to be in the same folder as the graph is going to be
|
||||
rendered from. Alternatively the absolute path to the files can be
|
||||
specified when including the graphics in the graph.
|
||||
|
||||
The files in the location pointed to by the path(s) specified as arguments
|
||||
to this method will be copied to the same temporary location where the
|
||||
graph is going to be rendered.
|
||||
The files in the location pointed to by the path(s) specified as
|
||||
arguments to this method will be copied to the same temporary location
|
||||
where the graph is going to be rendered.
|
||||
"""
|
||||
|
||||
if isinstance(file_paths, basestring):
|
||||
|
@ -1783,14 +1737,16 @@ class Dot(Graph):
|
|||
self.prog = prog
|
||||
|
||||
def set_graphviz_executables(self, paths):
|
||||
"""This method allows to manually specify the location of the GraphViz executables.
|
||||
"""This method allows to manually specify the location of the
|
||||
GraphViz executables.
|
||||
|
||||
The argument to this method should be a dictionary where the keys are as follows:
|
||||
The argument to this method should be a dictionary where the keys
|
||||
are as follows:
|
||||
|
||||
{'dot': '', 'twopi': '', 'neato': '', 'circo': '', 'fdp': ''}
|
||||
|
||||
and the values are the paths to the corresponding executable, including the name
|
||||
of the executable itself.
|
||||
and the values are the paths to the corresponding executable,
|
||||
including the name of the executable itself.
|
||||
"""
|
||||
|
||||
self.progs = paths
|
||||
|
@ -1893,9 +1849,11 @@ class Dot(Graph):
|
|||
raise InvocationException(
|
||||
'GraphViz\'s executable "%s" not found' % prog)
|
||||
|
||||
if not os.path.exists(self.progs[prog]) or not os.path.isfile(self.progs[prog]):
|
||||
if (not os.path.exists(self.progs[prog]) or
|
||||
not os.path.isfile(self.progs[prog])):
|
||||
raise InvocationException(
|
||||
'GraphViz\'s executable "%s" is not a file or doesn\'t exist' % self.progs[prog])
|
||||
'GraphViz\'s executable "%s" is not a file or doesn\'t exist'
|
||||
% self.progs[prog])
|
||||
|
||||
tmp_fd, tmp_name = tempfile.mkstemp()
|
||||
os.close(tmp_fd)
|
||||
|
@ -1910,7 +1868,8 @@ class Dot(Graph):
|
|||
f_data = f.read()
|
||||
f.close()
|
||||
|
||||
# And copy it under a file with the same name in the temporary directory
|
||||
# And copy it under a file with the same name in the
|
||||
# temporary directory
|
||||
f = open(os.path.join(tmp_dir, os.path.basename(img)), 'wb')
|
||||
f.write(f_data)
|
||||
f.close()
|
||||
|
@ -1949,7 +1908,6 @@ class Dot(Graph):
|
|||
if PY3:
|
||||
stderr_output = stderr_output.decode(sys.stderr.encoding)
|
||||
|
||||
#pid, status = os.waitpid(p.pid, 0)
|
||||
status = p.wait()
|
||||
|
||||
if status != 0:
|
||||
|
@ -1961,7 +1919,6 @@ class Dot(Graph):
|
|||
|
||||
# For each of the image files...
|
||||
for img in self.shape_files:
|
||||
|
||||
# remove it
|
||||
os.unlink(os.path.join(tmp_dir, os.path.basename(img)))
|
||||
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
"""Graphviz's dot language parser.
|
||||
# Graphviz's dot language parser.
|
||||
|
||||
The dotparser parses graphviz files in dot and dot files and transforms them
|
||||
into a class representation defined by pydot.
|
||||
# The dotparser parses graphviz files in dot and dot files and transforms them
|
||||
# into a class representation defined by pydot.
|
||||
|
||||
The module needs pyparsing (tested with version 1.2.2) and pydot
|
||||
# The module needs pyparsing (tested with version 1.2.2) and pydot
|
||||
|
||||
Author: Michael Krause <michael@krause-software.de>
|
||||
Fixes by: Ero Carrera <ero@dkbza.org>
|
||||
"""
|
||||
# Author: Michael Krause <michael@krause-software.de>
|
||||
# Fixes by: Ero Carrera <ero@dkbza.org>
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
__author__ = ['Michael Krause', 'Ero Carrera']
|
||||
__license__ = 'MIT'
|
||||
|
||||
import sys
|
||||
import pydot_ng as pydot
|
||||
import codecs
|
||||
|
@ -27,6 +23,9 @@ from pyparsing import (
|
|||
ParseResults, CharsNotIn, QuotedString
|
||||
)
|
||||
|
||||
__author__ = ['Michael Krause', 'Ero Carrera']
|
||||
__license__ = 'MIT'
|
||||
|
||||
|
||||
PY3 = not sys.version_info < (3, 0, 0)
|
||||
|
||||
|
@ -134,7 +133,8 @@ 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:
|
||||
|
@ -142,13 +142,15 @@ def update_parent_graph_hierarchy(g, parent_graph=None, level=0):
|
|||
|
||||
if key_name == 'edges' and len(key) == 2:
|
||||
for idx, vertex in enumerate(obj['points']):
|
||||
if isinstance(vertex, (pydot.Graph, pydot.Subgraph, pydot.Cluster)):
|
||||
if isinstance(vertex, (pydot.Graph, pydot.Subgraph,
|
||||
pydot.Cluster)):
|
||||
vertex.set_parent_graph(parent_graph)
|
||||
if isinstance(vertex, pydot.frozendict):
|
||||
if vertex['parent_graph'] is g:
|
||||
pass
|
||||
else:
|
||||
vertex['parent_graph'].set_parent_graph(parent_graph)
|
||||
vertex['parent_graph'].\
|
||||
set_parent_graph(parent_graph)
|
||||
|
||||
|
||||
def add_defaults(element, defaults):
|
||||
|
@ -158,7 +160,8 @@ def add_defaults(element, defaults):
|
|||
d[key] = value
|
||||
|
||||
|
||||
def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge=None):
|
||||
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:
|
||||
|
@ -181,7 +184,8 @@ def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge
|
|||
|
||||
elif isinstance(element, ParseResults):
|
||||
for e in element:
|
||||
add_elements(g, [e], defaults_graph, defaults_node, defaults_edge)
|
||||
add_elements(g, [e], defaults_graph, defaults_node,
|
||||
defaults_edge)
|
||||
|
||||
elif isinstance(element, DefaultStatement):
|
||||
if element.default_type == 'graph':
|
||||
|
@ -198,7 +202,8 @@ def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge
|
|||
defaults_edge.update(element.attrs)
|
||||
|
||||
else:
|
||||
raise ValueError("Unknown DefaultStatement: %s " % element.default_type)
|
||||
raise ValueError("Unknown DefaultStatement: {0} ".
|
||||
format(element.default_type))
|
||||
|
||||
elif isinstance(element, P_AttrList):
|
||||
g.obj_dict['attributes'].update(element.attrs)
|
||||
|
@ -290,7 +295,8 @@ def push_edge_stmt(str, loc, toks):
|
|||
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))
|
||||
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]
|
||||
|
@ -304,7 +310,8 @@ def push_edge_stmt(str, loc, toks):
|
|||
|
||||
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('')):
|
||||
if isinstance(n_next, P_AttrList) or not isinstance(n_next[0],
|
||||
type('')):
|
||||
continue
|
||||
|
||||
n_next_port = do_node_ports(n_next)
|
||||
|
@ -352,10 +359,6 @@ def graph_definition():
|
|||
rparen = Literal(")")
|
||||
equals = Literal("=")
|
||||
comma = Literal(",")
|
||||
# dot = Literal(".")
|
||||
# slash = Literal("/")
|
||||
# bslash = Literal("\\")
|
||||
# star = Literal("*")
|
||||
semi = Literal(";")
|
||||
at = Literal("@")
|
||||
minus = Literal("-")
|
||||
|
@ -372,7 +375,8 @@ def graph_definition():
|
|||
identifier = Word(alphanums + "_.").setName("identifier")
|
||||
|
||||
# dblQuotedString
|
||||
double_quoted_string = QuotedString('"', multiline=True, unquoteResults=False)
|
||||
double_quoted_string = QuotedString('"', multiline=True,
|
||||
unquoteResults=False)
|
||||
|
||||
noncomma_ = "".join([c for c in printables if c != ","])
|
||||
alphastring_ = OneOrMore(CharsNotIn(noncomma_ + ' '))
|
||||
|
@ -389,7 +393,7 @@ def graph_definition():
|
|||
|
||||
ID = (
|
||||
identifier | html_text |
|
||||
double_quoted_string | # .setParseAction(strip_quotes) |
|
||||
double_quoted_string |
|
||||
alphastring_
|
||||
).setName("ID")
|
||||
|
||||
|
@ -421,7 +425,8 @@ def graph_definition():
|
|||
lbrack.suppress() + Optional(a_list) + rbrack.suppress()
|
||||
).setName("attr_list")
|
||||
|
||||
attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt")
|
||||
attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).\
|
||||
setName("attr_stmt")
|
||||
|
||||
edgeop = (Literal("--") | Literal("->")).setName("edgeop")
|
||||
|
||||
|
@ -436,9 +441,11 @@ def graph_definition():
|
|||
edgeRHS = OneOrMore(edgeop + edge_point)
|
||||
edge_stmt = edge_point + edgeRHS + Optional(attr_list)
|
||||
|
||||
subgraph = Group(subgraph_ + Optional(ID) + graph_stmt).setName("subgraph")
|
||||
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())
|
||||
|
|
|
@ -39,25 +39,18 @@ MY_REGRESSION_TESTS_DIR = os.path.join(TEST_DIR, 'my_tests')
|
|||
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')
|
||||
|
||||
g = pydot.Dot(graph_name='Test', graph_type='digraph')
|
||||
|
||||
self.assertEqual(g.get_type(), 'digraph')
|
||||
|
||||
def test_add_style(self):
|
||||
|
||||
node = pydot.Node('mynode')
|
||||
node.add_style('abc')
|
||||
self.assertEqual(node.get_style(), 'abc')
|
||||
|
@ -67,7 +60,6 @@ class TestGraphAPI(unittest.TestCase):
|
|||
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')
|
||||
|
@ -75,10 +67,10 @@ class TestGraphAPI(unittest.TestCase):
|
|||
g.add_node(node)
|
||||
node.set('label', 'mine')
|
||||
|
||||
self.assertEqual(g.to_string(), 'digraph G {\nlegend [label=mine, shape=box];\n}\n')
|
||||
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}'
|
||||
g = pydot.graph_from_dot_data(d)
|
||||
attrs = g.get_edges()[0].get_attributes()
|
||||
|
@ -86,7 +78,6 @@ class TestGraphAPI(unittest.TestCase):
|
|||
self.assertEqual('decorate' in attrs, True)
|
||||
|
||||
def test_subgraphs(self):
|
||||
|
||||
g = pydot.Graph()
|
||||
s = pydot.Subgraph("foo")
|
||||
|
||||
|
@ -99,7 +90,6 @@ class TestGraphAPI(unittest.TestCase):
|
|||
self.assertEqual(g.get_subgraph_list()[0].get_name(), s.get_name())
|
||||
|
||||
def test_graph_pickling(self):
|
||||
|
||||
import pickle
|
||||
|
||||
g = pydot.Graph()
|
||||
|
@ -113,7 +103,6 @@ class TestGraphAPI(unittest.TestCase):
|
|||
self.assertEqual(type(pickle.dumps(g)), bytes)
|
||||
|
||||
def test_unicode_ids(self):
|
||||
|
||||
node1 = '"aánñoöüé€"'
|
||||
node2 = '"îôø®çßΩ"'
|
||||
|
||||
|
@ -139,7 +128,6 @@ class TestGraphAPI(unittest.TestCase):
|
|||
|
||||
@unittest.skip("failing checksum")
|
||||
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')
|
||||
|
||||
|
@ -154,29 +142,19 @@ class TestGraphAPI(unittest.TestCase):
|
|||
f.close()
|
||||
|
||||
g = pydot.graph_from_dot_data(graph_data)
|
||||
|
||||
g.set_shape_files(pngs)
|
||||
|
||||
jpe_data = g.create(format='jpe')
|
||||
|
||||
hexdigest = sha256(jpe_data).hexdigest()
|
||||
|
||||
hexdigest_original = self._render_with_graphviz(dot_file)
|
||||
|
||||
self.assertEqual(hexdigest, hexdigest_original)
|
||||
|
||||
def test_multiple_graphs(self):
|
||||
|
||||
graph_data = 'graph A { a->b };\ngraph B {c->d}'
|
||||
|
||||
graphs = pydot.graph_from_dot_data(graph_data)
|
||||
|
||||
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'),
|
||||
cwd=os.path.dirname(filename),
|
||||
|
@ -197,25 +175,16 @@ class TestGraphAPI(unittest.TestCase):
|
|||
if stdout_output:
|
||||
stdout_output = NULL_SEP.join(stdout_output)
|
||||
|
||||
#pid, status = os.waitpid(p.pid, 0)
|
||||
# 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 = pydot.parse_from_dot_data(graph_data)
|
||||
g = pydot.graph_from_dot_file(filename)
|
||||
|
||||
if not isinstance(g, list):
|
||||
g = [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):
|
||||
|
@ -230,10 +199,9 @@ class TestGraphAPI(unittest.TestCase):
|
|||
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()
|
||||
|
||||
|
@ -244,7 +212,6 @@ class TestGraphAPI(unittest.TestCase):
|
|||
original_data_hexdigest = self._render_with_graphviz(fname)
|
||||
except Exception:
|
||||
print('Failed rendering BAD(%s)' % dot)
|
||||
#print 'Error:', str(excp)
|
||||
raise
|
||||
|
||||
if parsed_data_hexdigest != original_data_hexdigest:
|
||||
|
@ -253,92 +220,67 @@ class TestGraphAPI(unittest.TestCase):
|
|||
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')
|
||||
|
||||
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.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.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.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(), '')
|
||||
|
||||
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.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)])
|
||||
|
||||
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.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.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')
|
||||
|
||||
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')
|
||||
|
||||
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')
|
||||
|
||||
|
@ -346,7 +288,6 @@ class TestGraphAPI(unittest.TestCase):
|
|||
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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue