From e2ee49285213095fefecc13f0cb9748ba4155f11 Mon Sep 17 00:00:00 2001 From: Peter Nowee Date: Sat, 29 May 2021 20:08:11 +0200 Subject: [PATCH 1/4] yapf --style pep8 # 0.31.0 --- dot_parser.py | 173 ++++++-------- pydot.py | 512 +++++++++++++++++++++++------------------ setup.py | 80 ++++--- test/pydot_unittest.py | 139 +++++------ 4 files changed, 463 insertions(+), 441 deletions(-) diff --git a/dot_parser.py b/dot_parser.py index a6b8ee0b..cfdcff4e 100644 --- a/dot_parser.py +++ b/dot_parser.py @@ -11,22 +11,16 @@ from __future__ import print_function import sys -from pyparsing import ( - nestedExpr, Literal, CaselessLiteral, - Word, OneOrMore, - Forward, - Group, Optional, Combine, - restOfLine, cStyleComment, nums, alphanums, - printables, - ParseException, ParseResults, CharsNotIn, - QuotedString) +from pyparsing import (nestedExpr, Literal, CaselessLiteral, Word, OneOrMore, + Forward, Group, Optional, Combine, restOfLine, + cStyleComment, nums, alphanums, printables, + ParseException, ParseResults, CharsNotIn, QuotedString) import pydot __author__ = ['Michael Krause', 'Ero Carrera'] __license__ = 'MIT' - PY3 = sys.version_info >= (3, 0, 0) if PY3: str_type = str @@ -35,15 +29,14 @@ class P_AttrList(object): - def __init__(self, toks): self.attrs = {} i = 0 while i < len(toks): attrname = toks[i] - if i+2 < len(toks) and toks[i+1] == '=': - attrvalue = toks[i+2] + if i + 2 < len(toks) and toks[i + 1] == '=': + attrvalue = toks[i + 2] i += 3 else: attrvalue = None @@ -56,14 +49,13 @@ def __repr__(self): class DefaultStatement(P_AttrList): - def __init__(self, default_type, attrs): self.default_type = default_type self.attrs = attrs def __repr__(self): - return "%s(%s, %r)" % (self.__class__.__name__, - self.default_type, self.attrs) + return "%s(%s, %r)" % (self.__class__.__name__, self.default_type, + self.attrs) top_graphs = list() @@ -75,9 +67,8 @@ def push_top_graph_stmt(str, loc, toks): for element in toks: - if (isinstance(element, (ParseResults, tuple, list)) and - len(element) == 1 and - isinstance(element[0], str_type)): + if (isinstance(element, (ParseResults, tuple, list)) + and len(element) == 1 and isinstance(element[0], str_type)): element = element[0] @@ -128,7 +119,7 @@ def update_parent_graph_hierarchy(g, parent_graph=None, level=0): if parent_graph is None: parent_graph = g - for key_name in ('edges',): + for key_name in ('edges', ): if isinstance(g, pydot.frozendict): item_dict = g @@ -140,8 +131,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: @@ -149,9 +140,9 @@ 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: @@ -168,8 +159,11 @@ 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: @@ -197,8 +191,8 @@ def add_elements(g, toks, defaults_graph=None, 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): @@ -219,9 +213,8 @@ def add_elements(g, toks, defaults_graph=None, defaults_edge.update(element.attrs) else: - raise ValueError( - 'Unknown DefaultStatement: {s}'.format( - s=element.default_type)) + raise ValueError('Unknown DefaultStatement: {s}'.format( + s=element.default_type)) elif isinstance(element, P_AttrList): @@ -268,8 +261,7 @@ def push_default_stmt(str, loc, toks): if default_type in ['graph', 'node', 'edge']: return DefaultStatement(default_type, attrs) else: - raise ValueError( - 'Unknown default statement: {s}'.format(s=toks)) + raise ValueError('Unknown default statement: {s}'.format(s=toks)) def push_attr_list(str, loc, toks): @@ -290,7 +282,7 @@ def get_port(node): 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 @@ -311,16 +303,17 @@ def push_edge_stmt(str, loc, toks): if isinstance(toks[2][0], ParseResults): - n_next_list = [[n.get_name(), ] for n in toks[2][0]] + n_next_list = [[ + n.get_name(), + ] for n in toks[2][0]] for n_next in [n for n in n_next_list]: n_next_port = do_node_ports(n_next) - e.append(pydot.Edge(n_prev, n_next[0]+n_next_port, **attrs)) + e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs)) elif isinstance(toks[2][0], pydot.Graph): - e.append(pydot.Edge(n_prev, - pydot.frozendict(toks[2][0].obj_dict), - **attrs)) + e.append( + pydot.Edge(n_prev, pydot.frozendict(toks[2][0].obj_dict), **attrs)) elif isinstance(toks[2][0], pydot.Node): @@ -338,18 +331,17 @@ def push_edge_stmt(str, loc, toks): for n_next in [n for n in tuple(toks)[2::2]]: - if (isinstance(n_next, P_AttrList) or - not isinstance(n_next[0], str_type)): + if (isinstance(n_next, P_AttrList) + or not isinstance(n_next[0], str_type)): continue n_next_port = do_node_ports(n_next) - e.append(pydot.Edge(n_prev, n_next[0]+n_next_port, **attrs)) + e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs)) - n_prev = n_next[0]+n_next_port + n_prev = n_next[0] + n_next_port else: - raise Exception( - 'Edge target {r} with type {s} unsupported.'.format( - r=toks[2][0], s=type(toks[2][0]))) + raise Exception('Edge target {r} with type {s} unsupported.'.format( + r=toks[2][0], s=type(toks[2][0]))) return e @@ -405,9 +397,10 @@ def graph_definition(): # token definitions identifier = Word(alphanums + "_.").setName("identifier") - double_quoted_string = QuotedString( - '"', multiline=True, unquoteResults=False, escChar='\\' - ) + double_quoted_string = QuotedString('"', + multiline=True, + unquoteResults=False, + escChar='\\') noncomma = "".join([c for c in printables if c != ","]) alphastring_ = OneOrMore(CharsNotIn(noncomma + ' ')) @@ -418,43 +411,34 @@ def parse_html(s, loc, toks): opener = '<' closer = '>' html_text = nestedExpr( - opener, closer, (CharsNotIn(opener + closer)) - ).setParseAction(parse_html).leaveWhitespace() + opener, closer, + (CharsNotIn(opener + + closer))).setParseAction(parse_html).leaveWhitespace() - ID = (identifier | html_text | double_quoted_string | - 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") 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") @@ -462,39 +446,34 @@ def parse_html(s, loc, toks): edgeop = (Literal("--") | Literal("->")).setName("edgeop") stmt_list = Forward() - graph_stmt = Group( - lbrace.suppress() + - Optional(stmt_list) + - rbrace.suppress() + - Optional(semi.suppress()) - ).setName("graph_stmt") + graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) + + rbrace.suppress() + + Optional(semi.suppress())).setName("graph_stmt") edge_point = Forward() 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())).setName("node_stmt") + node_stmt = (node_id + Optional(attr_list) + + Optional(semi.suppress())).setName("node_stmt") assignment = (ID + equals + righthand_id).setName("assignment") - stmt = (assignment | edge_stmt | attr_stmt | - subgraph | graph_stmt | node_stmt).setName("stmt") + stmt = (assignment | edge_stmt | attr_stmt | subgraph | graph_stmt + | node_stmt).setName("stmt") stmt_list << OneOrMore(stmt + Optional(semi.suppress())) - graphparser = OneOrMore( - (Optional(strict_) + Group((graph_ | digraph_)) + - Optional(ID) + graph_stmt).setResultsName("graph")) + graphparser = OneOrMore((Optional(strict_) + Group( + (graph_ | digraph_)) + Optional(ID) + + graph_stmt).setResultsName("graph")) - singleLineComment = Group( - "//" + restOfLine) | Group("#" + restOfLine) + singleLineComment = Group("//" + restOfLine) | Group("#" + restOfLine) # actions diff --git a/pydot.py b/pydot.py index c8c461d8..a2d53b61 100644 --- a/pydot.py +++ b/pydot.py @@ -14,81 +14,176 @@ try: import dot_parser except Exception as e: - warnings.warn( - "`pydot` could not import `dot_parser`, " - "so `pydot` will be unable to parse DOT files. " - "The error was: {e}".format(e=e)) - + warnings.warn("`pydot` could not import `dot_parser`, " + "so `pydot` will be unable to parse DOT files. " + "The error was: {e}".format(e=e)) __author__ = 'Ero Carrera' __version__ = '2.0.0.dev0' __license__ = 'MIT' - PY3 = sys.version_info >= (3, 0, 0) if PY3: str_type = str else: str_type = basestring - 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', - 'fontpath', 'fontsize', 'id', 'label', 'labeljust', 'labelloc', - 'landscape', 'layers', 'layersep', 'layout', 'levels', 'levelsgap', - 'lheight', 'lp', 'lwidth', 'margin', 'maxiter', 'mclimit', 'mindist', - 'mode', 'model', 'mosek', 'nodesep', 'nojustify', 'normalize', 'nslimit', - 'nslimit1', 'ordering', 'orientation', 'outputorder', 'overlap', - 'overlap_scaling', 'pack', 'packmode', 'pad', 'page', 'pagedir', - 'quadtree', 'quantum', 'rankdir', 'ranksep', 'ratio', 'remincross', - 'repulsiveforce', 'resolution', 'root', 'rotate', 'searchsize', 'sep', - 'showboxes', 'size', 'smoothing', 'sortv', 'splines', 'start', - 'stylesheet', 'target', 'truecolor', 'viewport', 'voro_margin', + 'Damping', + 'K', + 'URL', + 'aspect', + 'bb', + 'bgcolor', + 'center', + 'charset', + 'clusterrank', + 'colorscheme', + 'comment', + 'compound', + 'concentrate', + 'defaultdist', + 'dim', + 'dimen', + 'diredgeconstraints', + 'dpi', + 'epsilon', + 'esep', + 'fontcolor', + 'fontname', + 'fontnames', + 'fontpath', + 'fontsize', + 'id', + 'label', + 'labeljust', + 'labelloc', + 'landscape', + 'layers', + 'layersep', + 'layout', + 'levels', + 'levelsgap', + 'lheight', + 'lp', + 'lwidth', + 'margin', + 'maxiter', + 'mclimit', + 'mindist', + 'mode', + 'model', + 'mosek', + 'nodesep', + 'nojustify', + 'normalize', + 'nslimit', + 'nslimit1', + 'ordering', + 'orientation', + 'outputorder', + 'overlap', + 'overlap_scaling', + 'pack', + 'packmode', + 'pad', + 'page', + 'pagedir', + 'quadtree', + 'quantum', + 'rankdir', + 'ranksep', + 'ratio', + 'remincross', + 'repulsiveforce', + 'resolution', + 'root', + 'rotate', + 'searchsize', + 'sep', + 'showboxes', + 'size', + 'smoothing', + 'sortv', + 'splines', + 'start', + 'stylesheet', + 'target', + 'truecolor', + 'viewport', + 'voro_margin', # for subgraphs 'rank' } - EDGE_ATTRIBUTES = { - 'URL', 'arrowhead', 'arrowsize', 'arrowtail', - 'color', 'colorscheme', 'comment', 'constraint', 'decorate', 'dir', - 'edgeURL', 'edgehref', 'edgetarget', 'edgetooltip', 'fontcolor', - 'fontname', 'fontsize', 'headURL', 'headclip', 'headhref', 'headlabel', - 'headport', 'headtarget', 'headtooltip', 'href', 'id', 'label', - 'labelURL', 'labelangle', 'labeldistance', 'labelfloat', 'labelfontcolor', - 'labelfontname', 'labelfontsize', 'labelhref', 'labeltarget', - 'labeltooltip', 'layer', 'len', 'lhead', 'lp', 'ltail', 'minlen', - 'nojustify', 'penwidth', 'pos', 'samehead', 'sametail', 'showboxes', - 'style', 'tailURL', 'tailclip', 'tailhref', 'taillabel', 'tailport', - 'tailtarget', 'tailtooltip', 'target', 'tooltip', 'weight', - 'rank' + 'URL', 'arrowhead', 'arrowsize', 'arrowtail', 'color', 'colorscheme', + 'comment', 'constraint', 'decorate', 'dir', 'edgeURL', 'edgehref', + 'edgetarget', 'edgetooltip', 'fontcolor', 'fontname', 'fontsize', + 'headURL', 'headclip', 'headhref', 'headlabel', 'headport', 'headtarget', + 'headtooltip', 'href', 'id', 'label', 'labelURL', 'labelangle', + 'labeldistance', 'labelfloat', 'labelfontcolor', 'labelfontname', + 'labelfontsize', 'labelhref', 'labeltarget', 'labeltooltip', 'layer', + 'len', 'lhead', 'lp', 'ltail', 'minlen', 'nojustify', 'penwidth', 'pos', + 'samehead', 'sametail', 'showboxes', 'style', 'tailURL', 'tailclip', + 'tailhref', 'taillabel', 'tailport', 'tailtarget', 'tailtooltip', 'target', + 'tooltip', 'weight', 'rank' } - NODE_ATTRIBUTES = { - 'URL', 'color', 'colorscheme', 'comment', - 'distortion', 'fillcolor', 'fixedsize', 'fontcolor', 'fontname', - 'fontsize', 'group', 'height', 'id', 'image', 'imagescale', 'label', - 'labelloc', 'layer', 'margin', 'nojustify', 'orientation', 'penwidth', - 'peripheries', 'pin', 'pos', 'rects', 'regular', 'root', 'samplepoints', - 'shape', 'shapefile', 'showboxes', 'sides', 'skew', 'sortv', 'style', - 'target', 'tooltip', 'vertices', 'width', 'z', + 'URL', + 'color', + 'colorscheme', + 'comment', + 'distortion', + 'fillcolor', + 'fixedsize', + 'fontcolor', + 'fontname', + 'fontsize', + 'group', + 'height', + 'id', + 'image', + 'imagescale', + 'label', + 'labelloc', + 'layer', + 'margin', + 'nojustify', + 'orientation', + 'penwidth', + 'peripheries', + 'pin', + 'pos', + 'rects', + 'regular', + 'root', + 'samplepoints', + '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', - 'fillcolor', 'fontcolor', 'fontname', 'fontsize', 'label', 'labeljust', - 'labelloc', 'lheight', 'lp', 'lwidth', 'nojustify', 'pencolor', - 'penwidth', 'peripheries', 'sortv', 'style', 'target', 'tooltip' + 'K', 'URL', 'bgcolor', 'color', 'colorscheme', 'fillcolor', 'fontcolor', + 'fontname', 'fontsize', 'label', 'labeljust', 'labelloc', 'lheight', 'lp', + 'lwidth', 'nojustify', 'pencolor', 'penwidth', 'peripheries', 'sortv', + 'style', 'target', 'tooltip' } - DEFAULT_PROGRAMS = { 'dot', 'twopi', @@ -136,17 +231,17 @@ def call_graphviz(program, arguments, working_dir, **kwargs): 'SYSTEMROOT': os.environ.get('SYSTEMROOT', ''), } - program_with_args = [program, ] + arguments - - process = subprocess.Popen( - program_with_args, - env=env, - cwd=working_dir, - shell=False, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - **kwargs - ) + program_with_args = [ + program, + ] + arguments + + process = subprocess.Popen(program_with_args, + env=env, + cwd=working_dir, + shell=False, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + **kwargs) stdout_data, stderr_data = process.communicate() return stdout_data, stderr_data, process @@ -160,9 +255,9 @@ 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) __delitem__ = __setitem__ = clear = _blocked_attribute @@ -244,9 +339,10 @@ def needs_quotes(s): if chars and not id_re_dbl_quoted.match(s) and not id_re_html.match(s): return True - for test_re in [id_re_alpha_nums, id_re_num, - id_re_dbl_quoted, id_re_html, - id_re_alpha_nums_with_ports]: + for test_re in [ + id_re_alpha_nums, id_re_num, id_re_dbl_quoted, id_re_html, + id_re_alpha_nums_with_ports + ]: if test_re.match(s): return False @@ -271,9 +367,7 @@ def quote_if_necessary(s): return s if needs_quotes(s): - replace = {'"': r'\"', - "\n": r'\n', - "\r": r'\r'} + replace = {'"': r'\"', "\n": r'\n', "\r": r'\r'} for (a, b) in replace.items(): s = s.replace(a, b) @@ -370,7 +464,7 @@ def graph_from_adjacency_matrix(matrix, node_prefix=u'', directed=False): else: skip = 0 r = row - node_dest = skip+1 + node_dest = skip + 1 for e in r: if e: @@ -403,7 +497,7 @@ def graph_from_incidence_matrix(matrix, node_prefix='', directed=False): for node in row: if node: - nodes.append(c*node) + nodes.append(c * node) c += 1 nodes.sort() @@ -424,7 +518,6 @@ class Common(object): Should not be directly used, several classes are derived from this one. """ - def __getstate__(self): dict = copy.copy(self.obj_dict) return dict @@ -517,23 +610,19 @@ def create_attribute_methods(self, obj_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) - ) + 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): """General error handling class. """ - def __init__(self, value): self.value = value @@ -544,7 +633,6 @@ def __str__(self): class InvocationException(Exception): """Indicate problem while running any GraphViz executable. """ - def __init__(self, value): self.value = value @@ -564,7 +652,6 @@ class Node(Common): All the attributes defined in the Graphviz dot language should be supported. """ - def __init__(self, name='', obj_dict=None, **attrs): # # Nodes will take attributes of @@ -593,7 +680,7 @@ def __init__(self, name='', obj_dict=None, **attrs): port = None if isinstance(name, str_type) and not name.startswith('"'): idx = name.find(':') - if idx > 0 and idx+1 < len(name): + if idx > 0 and idx + 1 < len(name): name, port = name[:idx], name[idx:] if isinstance(name, int): @@ -642,9 +729,7 @@ def to_string(self): if value == '': value = '""' if value is not None: - node_attr.append( - '%s=%s' % (attr, quote_if_necessary(value)) - ) + node_attr.append('%s=%s' % (attr, quote_if_necessary(value))) else: node_attr.append(attr) @@ -690,15 +775,13 @@ class Edge(Common): edge_instance.obj_dict['attributes']['fontname'] """ - def __init__(self, src='', dst='', obj_dict=None, **attrs): self.obj_dict = dict() if isinstance(src, (Node, Subgraph, Cluster)): src = src.get_name() if isinstance(dst, (Node, Subgraph, Cluster)): dst = dst.get_name() - points = (quote_if_necessary(src), - quote_if_necessary(dst)) + points = (quote_if_necessary(src), quote_if_necessary(dst)) self.obj_dict['points'] = points if obj_dict is None: # Copy the attributes @@ -723,9 +806,7 @@ def get_destination(self): 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. @@ -739,28 +820,28 @@ def __eq__(self, edge): """ if not isinstance(edge, Edge): - raise Error('Can not compare and ' - 'edge to a non-edge object.') + raise Error('Can not compare and ' 'edge to a non-edge object.') if self.get_parent_graph().get_top_graph_type() == 'graph': # 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 if not PY3: + def __ne__(self, other): result = self.__eq__(other) if result is NotImplemented: @@ -777,13 +858,13 @@ 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: a = node_str[:node_port_idx] - b = node_str[node_port_idx+1:] + b = node_str[node_port_idx + 1:] node = quote_if_necessary(a) node += ':' + quote_if_necessary(b) @@ -804,11 +885,9 @@ def to_string(self): else: edge = [src] - if ( - self.get_parent_graph() and - self.get_parent_graph().get_top_graph_type() and - self.get_parent_graph().get_top_graph_type() == 'digraph' - ): + 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('->') else: @@ -828,8 +907,7 @@ def to_string(self): if value == '': value = '""' if value is not None: - edge_attr.append( - '%s=%s' % (attr, quote_if_necessary(value))) + edge_attr.append('%s=%s' % (attr, quote_if_necessary(value))) else: edge_attr.append(attr) @@ -876,10 +954,14 @@ class Graph(Common): graph_instance.obj_dict['attributes']['label'] 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): + 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 @@ -890,10 +972,9 @@ def __init__(self, graph_name='G', obj_dict=None, self.obj_dict['attributes'] = dict(attrs) if graph_type not in ['graph', 'digraph']: - raise Error(( - 'Invalid type "{t}". ' - 'Accepted graph types are: ' - 'graph, digraph').format(t=graph_type)) + raise Error(('Invalid type "{t}". ' + '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 @@ -1041,9 +1122,8 @@ def add_node(self, graph_node): None. """ if not isinstance(graph_node, Node): - raise TypeError( - 'add_node() received ' + - 'a non node class object: ' + str(graph_node)) + raise TypeError('add_node() received ' + + 'a non node class object: ' + str(graph_node)) node = self.get_node(graph_node.get_name()) @@ -1054,8 +1134,7 @@ def add_node(self, graph_node): 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()) @@ -1081,8 +1160,8 @@ def del_node(self, name, index=None): if name in self.obj_dict['nodes']: - if (index is not None and - index < len(self.obj_dict['nodes'][name])): + if (index is not None + and index < len(self.obj_dict['nodes'][name])): del self.obj_dict['nodes'][name][index] return True else: @@ -1105,9 +1184,10 @@ def get_node(self, name): if name in self.obj_dict['nodes']: - match.extend( - [Node(obj_dict=obj_dict) - for obj_dict in self.obj_dict['nodes'][name]]) + match.extend([ + Node(obj_dict=obj_dict) + for obj_dict in self.obj_dict['nodes'][name] + ]) return match @@ -1125,10 +1205,7 @@ def get_node_list(self): 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 - ]) + node_objs.extend([Node(obj_dict=obj_d) for obj_d in obj_dict_list]) return node_objs @@ -1139,12 +1216,10 @@ def add_edge(self, graph_edge): None. """ if not isinstance(graph_edge, Edge): - raise TypeError( - 'add_edge() received a non edge class object: ' + - str(graph_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] @@ -1185,8 +1260,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)])): + 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: @@ -1215,9 +1290,8 @@ def get_edge(self, src_or_list, dst=None): match = list() if edge_points in self.obj_dict['edges'] or ( - self.get_top_graph_type() == 'graph' and - edge_points_reverse in self.obj_dict['edges'] - ): + self.get_top_graph_type() == 'graph' + and 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)) @@ -1243,10 +1317,7 @@ def get_edge_list(self): 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 - ]) + edge_objs.extend([Edge(obj_dict=obj_d) for obj_d in obj_dict_list]) return edge_objs @@ -1256,8 +1327,8 @@ def add_subgraph(self, sgraph): It takes a subgraph object as its only argument and returns None. """ - if (not isinstance(sgraph, Subgraph) and - not isinstance(sgraph, Cluster)): + if (not isinstance(sgraph, Subgraph) + and not isinstance(sgraph, Cluster)): raise TypeError( 'add_subgraph() received a non subgraph class object:' + str(sgraph)) @@ -1268,8 +1339,7 @@ def add_subgraph(self, sgraph): sgraph_list.append(sgraph.obj_dict) else: - self.obj_dict['subgraphs'][sgraph.get_name()] = [ - sgraph.obj_dict] + 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()) @@ -1308,10 +1378,8 @@ def get_subgraph_list(self): 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 - ]) + sgraph_objs.extend( + [Subgraph(obj_dict=obj_d) for obj_d in obj_dict_list]) return sgraph_objs @@ -1343,18 +1411,16 @@ def to_string(self): if self.obj_dict.get('strict', None) is not None: - if (self == self.get_parent_graph() and - self.obj_dict['strict']): + if (self == self.get_parent_graph() and self.obj_dict['strict']): graph.append('strict ') graph_type = self.obj_dict['type'] - if (graph_type == 'subgraph' and - not self.obj_dict.get('show_keyword', True)): + if (graph_type == 'subgraph' + and not self.obj_dict.get('show_keyword', True)): graph_type = '' - s = '{type} {name} {{\n'.format( - type=graph_type, - name=self.obj_dict['name']) + s = '{type} {name} {{\n'.format(type=graph_type, + name=self.obj_dict['name']) graph.append(s) for attr in sorted(self.obj_dict['attributes']): @@ -1365,8 +1431,7 @@ def to_string(self): if val == '': val = '""' if val is not None: - graph.append('%s=%s' % - (attr, quote_if_necessary(val))) + graph.append('%s=%s' % (attr, quote_if_necessary(val))) else: graph.append(attr) @@ -1379,8 +1444,8 @@ def to_string(self): edge_obj_dicts.extend(self.obj_dict['edges'][k]) 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() @@ -1406,8 +1471,8 @@ def to_string(self): 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): + if (node.get_name() not in edge_src_set + and node.get_name() not in edge_dst_set): continue graph.append(node.to_string() + '\n') @@ -1415,8 +1480,8 @@ def to_string(self): elif obj['type'] == 'edge': edge = Edge(obj_dict=obj) - if (self.obj_dict.get('simplify', False) and - edge in edges_done): + if (self.obj_dict.get('simplify', False) + and edge in edges_done): continue graph.append(edge.to_string() + '\n') @@ -1424,7 +1489,7 @@ def to_string(self): else: sgraph = Subgraph(obj_dict=obj) - graph.append(sgraph.to_string()+'\n') + graph.append(sgraph.to_string() + '\n') graph.append('}\n') @@ -1466,13 +1531,18 @@ class Subgraph(Graph): # 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) + 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) if obj_dict is None: @@ -1510,19 +1580,23 @@ class Cluster(Graph): cluster_instance.obj_dict['attributes']['label'] 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, - simplify=simplify, **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) if obj_dict is None: self.obj_dict['type'] = 'subgraph' - self.obj_dict['name'] = quote_if_necessary('cluster_'+graph_name) + self.obj_dict['name'] = quote_if_necessary('cluster_' + graph_name) self.create_attribute_methods(CLUSTER_ATTRIBUTES) @@ -1534,21 +1608,17 @@ class Dot(Graph): a dot language file. It is a derived class of the base class 'Graph'. """ - def __init__(self, *argsl, **argsd): Graph.__init__(self, *argsl, **argsd) self.shape_files = list() self.formats = [ - 'canon', 'cmap', 'cmapx', - 'cmapx_np', 'dia', 'dot', - 'fig', 'gd', 'gd2', 'gif', - 'hpgl', 'imap', 'imap_np', 'ismap', - 'jpe', 'jpeg', 'jpg', 'mif', - 'mp', 'pcl', 'pdf', 'pic', 'plain', - 'plain-ext', 'png', 'ps', 'ps2', - 'svg', 'svgz', 'vml', 'vmlz', - 'vrml', 'vtx', 'wbmp', 'xdot', 'xlib'] + 'canon', 'cmap', 'cmapx', 'cmapx_np', 'dia', 'dot', 'fig', 'gd', + 'gd2', 'gif', 'hpgl', 'imap', 'imap_np', 'ismap', 'jpe', 'jpeg', + 'jpg', 'mif', 'mp', 'pcl', 'pdf', 'pic', 'plain', 'plain-ext', + 'png', 'ps', 'ps2', 'svg', 'svgz', 'vml', 'vmlz', 'vrml', 'vtx', + 'wbmp', 'xdot', 'xlib' + ] self.prog = 'dot' @@ -1556,23 +1626,20 @@ def __init__(self, *argsl, **argsd): # the methods enabling the creation # of output in any of the supported formats. for frmt in self.formats: - def new_method( - f=frmt, prog=self.prog, - encoding=None): + + def new_method(f=frmt, prog=self.prog, encoding=None): """Refer to docstring of method `create`.""" - return self.create( - format=f, prog=prog, encoding=encoding) + return self.create(format=f, prog=prog, encoding=encoding) + name = 'create_{fmt}'.format(fmt=frmt) self.__setattr__(name, new_method) - for frmt in self.formats+['raw']: - def new_method( - path, f=frmt, prog=self.prog, - encoding=None): + for frmt in self.formats + ['raw']: + + def new_method(path, f=frmt, prog=self.prog, encoding=None): """Refer to docstring of method `write.`""" - self.write( - path, format=f, prog=prog, - encoding=encoding) + self.write(path, format=f, prog=prog, encoding=encoding) + name = 'write_{fmt}'.format(fmt=frmt) self.__setattr__(name, new_method) @@ -1739,7 +1806,9 @@ def create(self, prog=None, format='ps', encoding=None): f.write(f_data) f.close() - arguments = ['-T{}'.format(format), ] + args + [tmp_name] + arguments = [ + '-T{}'.format(format), + ] + args + [tmp_name] try: stdout_data, stderr_data, process = call_graphviz( @@ -1750,8 +1819,7 @@ def create(self, prog=None, format='ps', encoding=None): except OSError as e: if e.errno == errno.ENOENT: args = list(e.args) - args[1] = '"{prog}" not found in path.'.format( - prog=prog) + args[1] = '"{prog}" not found in path.'.format(prog=prog) raise OSError(*args) else: raise @@ -1765,22 +1833,20 @@ def create(self, prog=None, format='ps', encoding=None): if process.returncode != 0: message = ( '"{prog}" with args {arguments} returned code: {code}\n\n' - 'stdout, stderr:\n {out}\n{err}\n' - ).format( - prog=prog, - arguments=arguments, - code=process.returncode, - out=stdout_data, - err=stderr_data, - ) - print(message) - - assert process.returncode == 0, ( - '"{prog}" with args {arguments} returned code: {code}'.format( + 'stdout, stderr:\n {out}\n{err}\n').format( prog=prog, arguments=arguments, code=process.returncode, + out=stdout_data, + err=stderr_data, ) - ) + print(message) + + assert process.returncode == 0, ( + '"{prog}" with args {arguments} returned code: {code}'.format( + prog=prog, + arguments=arguments, + code=process.returncode, + )) return stdout_data diff --git a/setup.py b/setup.py index 97da6968..ca48c4b5 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,6 @@ import os import re - CURRENT_DIR = os.path.dirname(__file__) @@ -29,43 +28,42 @@ def get_version(): return str(ast.literal_eval(version)) -setup( - name='pydot', - version=get_version(), - description="Python interface to Graphviz's Dot", - author='Ero Carrera', - author_email='ero.carrera@gmail.com', - maintainer='Peter Nowee', - maintainer_email='peter@peternowee.com', - url='https://github.com/pydot/pydot', - project_urls={ - "Changelog": "https://github.com/pydot/pydot/blob/master/ChangeLog", - "Bug Tracker": "https://github.com/pydot/pydot/issues", - }, - license='MIT', - keywords='graphviz dot graphs visualization', - platforms=['any'], - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Topic :: Scientific/Engineering :: Visualization', - 'Topic :: Software Development :: Libraries :: Python Modules'], - long_description=get_long_description(), - long_description_content_type="text/markdown", - py_modules=['pydot', 'dot_parser'], - install_requires=['pyparsing>=2.1.4'], - tests_require=['chardet']) +setup(name='pydot', + version=get_version(), + description="Python interface to Graphviz's Dot", + author='Ero Carrera', + author_email='ero.carrera@gmail.com', + maintainer='Peter Nowee', + maintainer_email='peter@peternowee.com', + url='https://github.com/pydot/pydot', + project_urls={ + "Changelog": "https://github.com/pydot/pydot/blob/master/ChangeLog", + "Bug Tracker": "https://github.com/pydot/pydot/issues", + }, + license='MIT', + keywords='graphviz dot graphs visualization', + platforms=['any'], + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', 'Operating System :: OS Independent', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Topic :: Scientific/Engineering :: Visualization', + 'Topic :: Software Development :: Libraries :: Python Modules' + ], + long_description=get_long_description(), + long_description_content_type="text/markdown", + py_modules=['pydot', 'dot_parser'], + install_requires=['pyparsing>=2.1.4'], + tests_require=['chardet']) diff --git a/test/pydot_unittest.py b/test/pydot_unittest.py index 4df26f8b..918f3474 100644 --- a/test/pydot_unittest.py +++ b/test/pydot_unittest.py @@ -19,20 +19,17 @@ import pydot import unittest - TEST_PROGRAM = 'dot' TESTS_DIR_1 = 'my_tests' TESTS_DIR_2 = 'graphs' class TestGraphAPI(unittest.TestCase): - def setUp(self): self._reset_graphs() def _reset_graphs(self): - self.graph_directed = pydot.Graph('testgraph', - graph_type='digraph') + self.graph_directed = pydot.Graph('testgraph', graph_type='digraph') def test_keep_graph_type(self): g = pydot.Dot(graph_name='Test', graph_type='graph') @@ -64,7 +61,7 @@ def test_create_simple_graph_with_node(self): def test_attribute_with_implicit_value(self): d = 'digraph {\na -> b[label="hi", decorate];\n}' graphs = pydot.graph_from_dot_data(d) - (g,) = graphs + (g, ) = graphs attrs = g.get_edges()[0].get_attributes() self.assertEqual('decorate' in attrs, True) @@ -78,10 +75,8 @@ def test_subgraphs(self): g.add_subgraph(s) - self.assertEqual(g.get_subgraphs()[0].get_name(), - s.get_name()) - self.assertEqual(g.get_subgraph_list()[0].get_name(), - s.get_name()) + self.assertEqual(g.get_subgraphs()[0].get_name(), s.get_name()) + self.assertEqual(g.get_subgraph_list()[0].get_name(), s.get_name()) def test_graph_pickling(self): g = pydot.Graph() @@ -109,7 +104,7 @@ def test_unicode_ids(self): 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 + (g2, ) = graphs self.assertEqual(g2.get_node(node1)[0].get_name(), node1) self.assertEqual(g2.get_node(node2)[0].get_name(), node2) @@ -125,18 +120,16 @@ def test_graph_simplify(self): g.add_edge(pydot.Edge('b', 'a')) g.add_edge(pydot.Edge('b', 'a')) test_combinations = [ - ('graph', False, - 'graph G { a -- b; a -- b; b -- a; b -- a; }'), - ('graph', True, - 'graph G { a -- b; }'), + ('graph', False, 'graph G { a -- b; a -- b; b -- a; b -- a; }'), + ('graph', True, 'graph G { a -- b; }'), ('digraph', False, 'digraph G { a -> b; a -> b; b -> a; b -> a; }'), - ('digraph', True, - 'digraph G { a -> b; b -> a; }')] + ('digraph', True, 'digraph G { a -> b; b -> a; }') + ] expected_concat = observed_concat = '' for (graph_type, simplify, expected) in test_combinations: expected_concat += 'graph_type %s, simplify %s: %s\n' % ( - graph_type, simplify, expected) + graph_type, simplify, expected) g.set_type(graph_type) g.set_simplify(simplify) try: @@ -144,7 +137,7 @@ def test_graph_simplify(self): except (NameError, TypeError) as e: observed = '%s: %s' % (type(e).__name__, e) observed_concat += 'graph_type %s, simplify %s: %s\n' % ( - graph_type, simplify, observed) + graph_type, simplify, observed) self.maxDiff = None self.assertMultiLineEqual(expected_concat, observed_concat) @@ -159,8 +152,7 @@ def test_graph_with_shapefiles(self): pngs = [ os.path.join(shapefile_dir, fname) - for fname in os.listdir(shapefile_dir) - if fname.endswith('.png') + for fname in os.listdir(shapefile_dir) if fname.endswith('.png') ] f = open(dot_file, 'rt') @@ -168,14 +160,14 @@ def test_graph_with_shapefiles(self): f.close() graphs = pydot.graph_from_dot_data(graph_data) - (g,) = graphs + (g, ) = graphs g.set_shape_files(pngs) jpe_data = g.create(format='jpe') hexdigest = sha256(jpe_data).hexdigest() - hexdigest_original = self._render_with_graphviz( - dot_file, encoding='ascii') + hexdigest_original = self._render_with_graphviz(dot_file, + encoding='ascii') self.assertEqual(hexdigest, hexdigest_original) def test_multiple_graphs(self): @@ -190,7 +182,9 @@ def _render_with_graphviz(self, filename, encoding): with io.open(filename, 'rt', encoding=encoding) as stdin: stdout_data, stderr_data, process = pydot.call_graphviz( program=TEST_PROGRAM, - arguments=['-Tjpe', ], + arguments=[ + '-Tjpe', + ], working_dir=os.path.dirname(filename), stdin=stdin, ) @@ -202,8 +196,8 @@ def _render_with_pydot(self, filename, encoding): c = pydot.graph_from_dot_file(filename, encoding=encoding) jpe_data = bytearray() for g in c: - jpe_data.extend(g.create(prog=TEST_PROGRAM, format='jpe', - encoding=encoding)) + jpe_data.extend( + g.create(prog=TEST_PROGRAM, format='jpe', encoding=encoding)) return sha256(jpe_data).hexdigest() def test_my_regression_tests(self): @@ -216,11 +210,10 @@ def test_graphviz_regression_tests(self): def _render_and_compare_dot_files(self, directory): # files that confuse `chardet` - encodings = { - 'Latin1.dot': 'latin-1'} + encodings = {'Latin1.dot': 'latin-1'} dot_files = [ - fname for fname in os.listdir(directory) - if fname.endswith('.dot')] + fname for fname in os.listdir(directory) if fname.endswith('.dot') + ] for fname in dot_files: fpath = os.path.join(directory, fname) with open(fpath, 'rb') as f: @@ -241,38 +234,30 @@ def test_numeric_node_id(self): 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(), '' - ) + 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() @@ -281,27 +266,27 @@ def test_names_of_a_thousand_nodes(self): 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') + 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() @@ -327,34 +312,29 @@ def test_edge_equality_basics_3_same_points_not_not_equal(self): def test_edge_point_namestr(self): self._reset_graphs() self.graph_directed.add_edge(pydot.Edge('a', 'b')) - self.assertEqual( - self.graph_directed.get_edges()[0].to_string(), 'a -> b;') + self.assertEqual(self.graph_directed.get_edges()[0].to_string(), + 'a -> b;') def test_edge_point_object_node(self): self._reset_graphs() 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;') + 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.assertEqual( - self.graph_directed.get_edges()[0].to_string(), 'a -> b;') + 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.assertEqual( - self.graph_directed.get_edges()[0].to_string(), - 'cluster_a -> cluster_b;' - ) + pydot.Edge(pydot.Cluster('a'), pydot.Cluster('b'))) + self.assertEqual(self.graph_directed.get_edges()[0].to_string(), + 'cluster_a -> cluster_b;') def test_graph_from_adjacency_matrix(self): g = pydot.graph_from_adjacency_matrix( @@ -371,8 +351,8 @@ def test_graph_from_incidence_matrix(self): [[-1, 1, 0], [1, -1, 0], [0, 1, -1]], directed=True) s = ' '.join(g.to_string().split()) self.assertEqual(s, 'digraph G { 1 -> 2; 2 -> 1; 3 -> 2; }') - g = pydot.graph_from_incidence_matrix( - [[1, 1, 0], [0, 1, 1]], directed=False) + g = pydot.graph_from_incidence_matrix([[1, 1, 0], [0, 1, 1]], + directed=False) s = ' '.join(g.to_string().split()) self.assertEqual(s, 'graph G { 1 -- 2; 2 -- 3; }') @@ -381,18 +361,17 @@ def check_path(): not_check = parse_args() if not_check: return - assert not os.path.isfile('setup.py'), ( - 'running out of source does not ' - 'test the installed `pydot`.') + assert not os.path.isfile('setup.py'), ('running out of source does not ' + 'test the installed `pydot`.') def parse_args(): """Return arguments.""" parser = argparse.ArgumentParser() - parser.add_argument( - '--no-check', action='store_true', - help=('do not require that no `setup.py` be present ' - 'in the current working directory.')) + parser.add_argument('--no-check', + action='store_true', + help=('do not require that no `setup.py` be present ' + 'in the current working directory.')) args, unknown = parser.parse_known_args() # avoid confusing `unittest` sys.argv = [sys.argv[0]] + unknown From 6358e1b54e45147ac89b3d86baa4365cd2ddf24b Mon Sep 17 00:00:00 2001 From: Peter Nowee Date: Mon, 31 May 2021 15:10:01 +0200 Subject: [PATCH 2/4] format-yapf-pep8: Manual corrections --- pydot.py | 17 ++++++----------- setup.py | 2 +- test/pydot_unittest.py | 8 ++++---- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/pydot.py b/pydot.py index a2d53b61..651b13e7 100644 --- a/pydot.py +++ b/pydot.py @@ -111,10 +111,8 @@ 'target', 'truecolor', 'viewport', - 'voro_margin', - # for subgraphs - 'rank' -} + 'voro_margin' +} | {'rank'} # for subgraphs EDGE_ATTRIBUTES = { 'URL', 'arrowhead', 'arrowsize', 'arrowtail', 'color', 'colorscheme', @@ -171,11 +169,8 @@ 'tooltip', 'vertices', 'width', - 'z', - # The following are attributes dot2tex - 'texlbl', - 'texmode' -} + 'z' +} | {'texlbl', 'texmode'} # The last set contains attributes dot2tex CLUSTER_ATTRIBUTES = { 'K', 'URL', 'bgcolor', 'color', 'colorscheme', 'fillcolor', 'fontcolor', @@ -367,7 +362,7 @@ def quote_if_necessary(s): return s if needs_quotes(s): - replace = {'"': r'\"', "\n": r'\n', "\r": r'\r'} + replace = {'"': r'\"', "\n": r'\n', "\r": r'\r',} for (a, b) in replace.items(): s = s.replace(a, b) @@ -820,7 +815,7 @@ def __eq__(self, edge): """ if not isinstance(edge, Edge): - raise Error('Can not compare and ' 'edge to a non-edge object.') + raise Error('Can not compare and edge to a non-edge object.') if self.get_parent_graph().get_top_graph_type() == 'graph': diff --git a/setup.py b/setup.py index ca48c4b5..08255eba 100644 --- a/setup.py +++ b/setup.py @@ -60,7 +60,7 @@ def get_version(): 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Topic :: Scientific/Engineering :: Visualization', - 'Topic :: Software Development :: Libraries :: Python Modules' + 'Topic :: Software Development :: Libraries :: Python Modules', ], long_description=get_long_description(), long_description_content_type="text/markdown", diff --git a/test/pydot_unittest.py b/test/pydot_unittest.py index 918f3474..93bc9292 100644 --- a/test/pydot_unittest.py +++ b/test/pydot_unittest.py @@ -120,11 +120,11 @@ def test_graph_simplify(self): g.add_edge(pydot.Edge('b', 'a')) g.add_edge(pydot.Edge('b', 'a')) test_combinations = [ - ('graph', False, 'graph G { a -- b; a -- b; b -- a; b -- a; }'), - ('graph', True, 'graph G { a -- b; }'), + ('graph', False, 'graph G { a -- b; a -- b; b -- a; b -- a; }',), + ('graph', True, 'graph G { a -- b; }',), ('digraph', False, - 'digraph G { a -> b; a -> b; b -> a; b -> a; }'), - ('digraph', True, 'digraph G { a -> b; b -> a; }') + 'digraph G { a -> b; a -> b; b -> a; b -> a; }',), + ('digraph', True, 'digraph G { a -> b; b -> a; }',) ] expected_concat = observed_concat = '' for (graph_type, simplify, expected) in test_combinations: From d05a69483582aad4da710d138469bd92ab13bc5c Mon Sep 17 00:00:00 2001 From: Peter Nowee Date: Mon, 31 May 2021 15:10:01 +0200 Subject: [PATCH 3/4] format-yapf-pep8: Second run --- pydot.py | 149 +++++++---------------------------------- setup.py | 3 +- test/pydot_unittest.py | 24 +++++-- 3 files changed, 43 insertions(+), 133 deletions(-) diff --git a/pydot.py b/pydot.py index 651b13e7..007c8b36 100644 --- a/pydot.py +++ b/pydot.py @@ -29,89 +29,19 @@ str_type = basestring 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', - 'fontpath', - 'fontsize', - 'id', - 'label', - 'labeljust', - 'labelloc', - 'landscape', - 'layers', - 'layersep', - 'layout', - 'levels', - 'levelsgap', - 'lheight', - 'lp', - 'lwidth', - 'margin', - 'maxiter', - 'mclimit', - 'mindist', - 'mode', - 'model', - 'mosek', - 'nodesep', - 'nojustify', - 'normalize', - 'nslimit', - 'nslimit1', - 'ordering', - 'orientation', - 'outputorder', - 'overlap', - 'overlap_scaling', - 'pack', - 'packmode', - 'pad', - 'page', - 'pagedir', - 'quadtree', - 'quantum', - 'rankdir', - 'ranksep', - 'ratio', - 'remincross', - 'repulsiveforce', - 'resolution', - 'root', - 'rotate', - 'searchsize', - 'sep', - 'showboxes', - 'size', - 'smoothing', - 'sortv', - 'splines', - 'start', - 'stylesheet', - 'target', - 'truecolor', - 'viewport', - 'voro_margin' + 'Damping', 'K', 'URL', 'aspect', 'bb', 'bgcolor', 'center', 'charset', + 'clusterrank', 'colorscheme', 'comment', 'compound', 'concentrate', + 'defaultdist', 'dim', 'dimen', 'diredgeconstraints', 'dpi', 'epsilon', + 'esep', 'fontcolor', 'fontname', 'fontnames', 'fontpath', 'fontsize', 'id', + 'label', 'labeljust', 'labelloc', 'landscape', 'layers', 'layersep', + 'layout', 'levels', 'levelsgap', 'lheight', 'lp', 'lwidth', 'margin', + 'maxiter', 'mclimit', 'mindist', 'mode', 'model', 'mosek', 'nodesep', + 'nojustify', 'normalize', 'nslimit', 'nslimit1', 'ordering', 'orientation', + 'outputorder', 'overlap', 'overlap_scaling', 'pack', 'packmode', 'pad', + 'page', 'pagedir', 'quadtree', 'quantum', 'rankdir', 'ranksep', 'ratio', + 'remincross', 'repulsiveforce', 'resolution', 'root', 'rotate', + 'searchsize', 'sep', 'showboxes', 'size', 'smoothing', 'sortv', 'splines', + 'start', 'stylesheet', 'target', 'truecolor', 'viewport', 'voro_margin' } | {'rank'} # for subgraphs EDGE_ATTRIBUTES = { @@ -129,47 +59,12 @@ } NODE_ATTRIBUTES = { - 'URL', - 'color', - 'colorscheme', - 'comment', - 'distortion', - 'fillcolor', - 'fixedsize', - 'fontcolor', - 'fontname', - 'fontsize', - 'group', - 'height', - 'id', - 'image', - 'imagescale', - 'label', - 'labelloc', - 'layer', - 'margin', - 'nojustify', - 'orientation', - 'penwidth', - 'peripheries', - 'pin', - 'pos', - 'rects', - 'regular', - 'root', - 'samplepoints', - 'shape', - 'shapefile', - 'showboxes', - 'sides', - 'skew', - 'sortv', - 'style', - 'target', - 'tooltip', - 'vertices', - 'width', - 'z' + 'URL', 'color', 'colorscheme', 'comment', 'distortion', 'fillcolor', + 'fixedsize', 'fontcolor', 'fontname', 'fontsize', 'group', 'height', 'id', + 'image', 'imagescale', 'label', 'labelloc', 'layer', 'margin', 'nojustify', + 'orientation', 'penwidth', 'peripheries', 'pin', 'pos', 'rects', 'regular', + 'root', 'samplepoints', 'shape', 'shapefile', 'showboxes', 'sides', 'skew', + 'sortv', 'style', 'target', 'tooltip', 'vertices', 'width', 'z' } | {'texlbl', 'texmode'} # The last set contains attributes dot2tex CLUSTER_ATTRIBUTES = { @@ -362,7 +257,11 @@ def quote_if_necessary(s): return s if needs_quotes(s): - replace = {'"': r'\"', "\n": r'\n', "\r": r'\r',} + replace = { + '"': r'\"', + "\n": r'\n', + "\r": r'\r', + } for (a, b) in replace.items(): s = s.replace(a, b) diff --git a/setup.py b/setup.py index 08255eba..70c61323 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,8 @@ def get_version(): 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', 'Operating System :: OS Independent', + 'Natural Language :: English', + 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', diff --git a/test/pydot_unittest.py b/test/pydot_unittest.py index 93bc9292..064698f6 100644 --- a/test/pydot_unittest.py +++ b/test/pydot_unittest.py @@ -119,13 +119,23 @@ def test_graph_simplify(self): g.add_edge(pydot.Edge('a', 'b')) g.add_edge(pydot.Edge('b', 'a')) g.add_edge(pydot.Edge('b', 'a')) - test_combinations = [ - ('graph', False, 'graph G { a -- b; a -- b; b -- a; b -- a; }',), - ('graph', True, 'graph G { a -- b; }',), - ('digraph', False, - 'digraph G { a -> b; a -> b; b -> a; b -> a; }',), - ('digraph', True, 'digraph G { a -> b; b -> a; }',) - ] + test_combinations = [( + 'graph', + False, + 'graph G { a -- b; a -- b; b -- a; b -- a; }', + ), ( + 'graph', + True, + 'graph G { a -- b; }', + ), ( + 'digraph', + False, + 'digraph G { a -> b; a -> b; b -> a; b -> a; }', + ), ( + 'digraph', + True, + 'digraph G { a -> b; b -> a; }', + )] expected_concat = observed_concat = '' for (graph_type, simplify, expected) in test_combinations: expected_concat += 'graph_type %s, simplify %s: %s\n' % ( From 1fa5fcca7e4cbc0442dea173bea185e27196f994 Mon Sep 17 00:00:00 2001 From: Peter Nowee Date: Mon, 31 May 2021 15:10:02 +0200 Subject: [PATCH 4/4] format-yapf-pep8: Config changes, Third run --- .style.yapf | 3 +++ dot_parser.py | 2 ++ pydot.py | 9 +++++++++ test/pydot_unittest.py | 1 + 4 files changed, 15 insertions(+) create mode 100644 .style.yapf diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 00000000..6fb204a7 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,3 @@ +[style] +based_on_style=pep8 +blank_line_before_nested_class_or_def=True diff --git a/dot_parser.py b/dot_parser.py index cfdcff4e..a6dd2069 100644 --- a/dot_parser.py +++ b/dot_parser.py @@ -29,6 +29,7 @@ class P_AttrList(object): + def __init__(self, toks): self.attrs = {} i = 0 @@ -49,6 +50,7 @@ def __repr__(self): class DefaultStatement(P_AttrList): + def __init__(self, default_type, attrs): self.default_type = default_type self.attrs = attrs diff --git a/pydot.py b/pydot.py index 007c8b36..9c4d5d62 100644 --- a/pydot.py +++ b/pydot.py @@ -145,6 +145,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.') @@ -412,6 +413,7 @@ class Common(object): Should not be directly used, several classes are derived from this one. """ + def __getstate__(self): dict = copy.copy(self.obj_dict) return dict @@ -517,6 +519,7 @@ def create_attribute_methods(self, obj_attributes): class Error(Exception): """General error handling class. """ + def __init__(self, value): self.value = value @@ -527,6 +530,7 @@ def __str__(self): class InvocationException(Exception): """Indicate problem while running any GraphViz executable. """ + def __init__(self, value): self.value = value @@ -546,6 +550,7 @@ class Node(Common): All the attributes defined in the Graphviz dot language should be supported. """ + def __init__(self, name='', obj_dict=None, **attrs): # # Nodes will take attributes of @@ -669,6 +674,7 @@ class Edge(Common): edge_instance.obj_dict['attributes']['fontname'] """ + def __init__(self, src='', dst='', obj_dict=None, **attrs): self.obj_dict = dict() if isinstance(src, (Node, Subgraph, Cluster)): @@ -848,6 +854,7 @@ class Graph(Common): graph_instance.obj_dict['attributes']['label'] graph_instance.obj_dict['attributes']['fontname'] """ + def __init__(self, graph_name='G', obj_dict=None, @@ -1474,6 +1481,7 @@ class Cluster(Graph): cluster_instance.obj_dict['attributes']['label'] cluster_instance.obj_dict['attributes']['fontname'] """ + def __init__(self, graph_name='subG', obj_dict=None, @@ -1502,6 +1510,7 @@ class Dot(Graph): a dot language file. It is a derived class of the base class 'Graph'. """ + def __init__(self, *argsl, **argsd): Graph.__init__(self, *argsl, **argsd) diff --git a/test/pydot_unittest.py b/test/pydot_unittest.py index 064698f6..5a0bd434 100644 --- a/test/pydot_unittest.py +++ b/test/pydot_unittest.py @@ -25,6 +25,7 @@ class TestGraphAPI(unittest.TestCase): + def setUp(self): self._reset_graphs()