[Python-modules-commits] [pydot] 02/14: support python3

Sandro Tosi morph at moszumanska.debian.org
Sat Nov 25 19:47:21 UTC 2017


This is an automated email from the git hooks/post-receive script.

morph pushed a commit to branch master
in repository pydot.

commit 36cdebbe253bdf22bce2b74070d1111f098a66b1
Author: Sandro Tosi <morph at debian.org>
Date:   Sun Jan 10 00:25:45 2016 +0000

    support python3
---
 dot_parser.py |  429 ++++++++--------
 pydot.py      | 1553 +++++++++++++++++++++++++++------------------------------
 setup.py      |    6 +-
 3 files changed, 954 insertions(+), 1034 deletions(-)

diff --git a/dot_parser.py b/dot_parser.py
index dedd61a..4cdd482 100644
--- a/dot_parser.py
+++ b/dot_parser.py
@@ -1,4 +1,3 @@
-# -*- coding: Latin-1 -*-
 """Graphviz's dot language parser.
 
 The dotparser parses graphviz files in dot and dot files and transforms them
@@ -10,236 +9,215 @@ Author: Michael Krause <michael at krause-software.de>
 Fixes by: Ero Carrera <ero at dkbza.org>
 """
 
+from __future__ import division, print_function
+
 __author__ = ['Michael Krause', 'Ero Carrera']
 __license__ = 'MIT'
 
-
 import sys
-import glob
 import pydot
-import re
 import codecs
 
 from pyparsing import __version__ as pyparsing_version
 
-from pyparsing import ( nestedExpr, Literal, CaselessLiteral, Word, Upcase, OneOrMore, ZeroOrMore,
-    Forward, NotAny, delimitedList, oneOf, Group, Optional, Combine, alphas, nums,
-    restOfLine, cStyleComment, nums, alphanums, printables, empty, quotedString,
-    ParseException, ParseResults, CharsNotIn, _noncomma, dblQuotedString, QuotedString, ParserElement )
+from pyparsing import (
+    nestedExpr, Literal, CaselessLiteral, Word, OneOrMore,
+    Forward, Group, Optional, Combine, nums, restOfLine,
+    cStyleComment, alphanums, printables, ParseException,
+    ParseResults, CharsNotIn, QuotedString
+    )
+
+
+PY3 = not sys.version_info < (3, 0, 0)
+
+if PY3:
+    basestring = str
 
 
 class P_AttrList:
 
     def __init__(self, toks):
-
         self.attrs = {}
         i = 0
-        
+
         while i < len(toks):
             attrname = toks[i]
-            if i+2 < len(toks) and toks[i+1] == '=':
-                attrvalue = toks[i+2]
+            if i + 2 < len(toks) and toks[i + 1] == '=':
+                attrvalue = toks[i + 2]
                 i += 3
             else:
                 attrvalue = None
                 i += 1
-                
+
             self.attrs[attrname] = attrvalue
-            
-            
-    def __repr__(self):
 
+    def __repr__(self):
         return "%s(%r)" % (self.__class__.__name__, self.attrs)
 
 
-
 class DefaultStatement(P_AttrList):
 
     def __init__(self, default_type, attrs):
-
         self.default_type = default_type
         self.attrs = attrs
 
     def __repr__(self):
-
-        return "%s(%s, %r)" % (self.__class__.__name__,
-            self.default_type, self.attrs)
+        return "%s(%s, %r)" % (
+            self.__class__.__name__,
+            self.default_type, self.attrs
+            )
 
 
 top_graphs = list()
 
-def push_top_graph_stmt(str, loc, toks):
 
+def push_top_graph_stmt(str, loc, toks):
     attrs = {}
     g = None
-    
+
     for element in toks:
-    
-        if( isinstance(element, (ParseResults, tuple, list)) and
-            len(element) == 1 and isinstance(element[0], basestring) ):
-            
+        if (isinstance(element, (ParseResults, tuple, list)) and
+                len(element) == 1 and isinstance(element[0], basestring)):
             element = element[0]
-            
+
         if element == 'strict':
             attrs['strict'] = True
-            
-        elif element in ['graph', 'digraph']:
 
+        elif element in ['graph', 'digraph']:
             attrs = {}
-            
+
             g = pydot.Dot(graph_type=element, **attrs)
             attrs['type'] = element
-            
-            top_graphs.append( g )
-            
-        elif isinstance( element, basestring):
-            g.set_name( element )
-            
+
+            top_graphs.append(g)
+
+        elif isinstance(element, basestring):
+            g.set_name(element)
+
         elif isinstance(element, pydot.Subgraph):
-        
-            g.obj_dict['attributes'].update( element.obj_dict['attributes'] )
-            g.obj_dict['edges'].update( element.obj_dict['edges'] )
-            g.obj_dict['nodes'].update( element.obj_dict['nodes'] )
-            g.obj_dict['subgraphs'].update( element.obj_dict['subgraphs'] )
-            
+            g.obj_dict['attributes'].update(element.obj_dict['attributes'])
+            g.obj_dict['edges'].update(element.obj_dict['edges'])
+            g.obj_dict['nodes'].update(element.obj_dict['nodes'])
+            g.obj_dict['subgraphs'].update(element.obj_dict['subgraphs'])
             g.set_parent_graph(g)
-            
+
         elif isinstance(element, P_AttrList):
             attrs.update(element.attrs)
 
         elif isinstance(element, (ParseResults, list)):
             add_elements(g, element)
-            
+
         else:
-            raise ValueError, "Unknown element statement: %r " % element
-    
-    
+            raise ValueError("Unknown element statement: %r " % element)
+
     for g in top_graphs:
         update_parent_graph_hierarchy(g)
-    
-    if len( top_graphs ) == 1:
+
+    if len(top_graphs) == 1:
         return top_graphs[0]
-        
+
     return top_graphs
 
 
 def update_parent_graph_hierarchy(g, parent_graph=None, level=0):
-
-
     if parent_graph is None:
         parent_graph = g
-        
-    for key_name in ('edges',):
 
+    for key_name in ('edges',):
         if isinstance(g, pydot.frozendict):
             item_dict = g
         else:
             item_dict = g.obj_dict
-            
-        if not item_dict.has_key( key_name ):
+
+        if key_name not in item_dict:
             continue
 
         for key, objs in item_dict[key_name].items():
             for obj in objs:
-                if 'parent_graph' in obj and obj['parent_graph'].get_parent_graph()==g:
+                if 'parent_graph' in obj and obj['parent_graph'].get_parent_graph() == g:
                     if obj['parent_graph'] is g:
                         pass
                     else:
                         obj['parent_graph'].set_parent_graph(parent_graph)
 
                 if key_name == 'edges' and len(key) == 2:
-                    for idx, vertex in enumerate( obj['points'] ):
-                        if isinstance( vertex, (pydot.Graph, pydot.Subgraph, pydot.Cluster)):
+                    for idx, vertex in enumerate(obj['points']):
+                        if isinstance(vertex, (pydot.Graph, pydot.Subgraph, pydot.Cluster)):
                             vertex.set_parent_graph(parent_graph)
-                        if isinstance( vertex, pydot.frozendict):
+                        if isinstance(vertex, pydot.frozendict):
                             if vertex['parent_graph'] is g:
                                 pass
                             else:
                                 vertex['parent_graph'].set_parent_graph(parent_graph)
 
 
-
 def add_defaults(element, defaults):
-
     d = element.__dict__
     for key, value in defaults.items():
         if not d.get(key):
             d[key] = value
 
 
-
 def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge=None):
-    
     if defaults_graph is None:
         defaults_graph = {}
     if defaults_node is None:
         defaults_node = {}
     if defaults_edge is None:
         defaults_edge = {}
-        
+
     for elm_idx, element in enumerate(toks):
-        
         if isinstance(element, (pydot.Subgraph, pydot.Cluster)):
-        
             add_defaults(element, defaults_graph)
             g.add_subgraph(element)
-            
+
         elif isinstance(element, pydot.Node):
-        
             add_defaults(element, defaults_node)
             g.add_node(element)
-            
+
         elif isinstance(element, pydot.Edge):
-        
             add_defaults(element, defaults_edge)
             g.add_edge(element)
-            
+
         elif isinstance(element, ParseResults):
-        
             for e in element:
                 add_elements(g, [e], defaults_graph, defaults_node, defaults_edge)
-                
+
         elif isinstance(element, DefaultStatement):
-        
             if element.default_type == 'graph':
-            
                 default_graph_attrs = pydot.Node('graph', **element.attrs)
                 g.add_node(default_graph_attrs)
 
             elif element.default_type == 'node':
-            
                 default_node_attrs = pydot.Node('node', **element.attrs)
                 g.add_node(default_node_attrs)
 
             elif element.default_type == 'edge':
-            
                 default_edge_attrs = pydot.Node('edge', **element.attrs)
                 g.add_node(default_edge_attrs)
                 defaults_edge.update(element.attrs)
 
             else:
-                raise ValueError, "Unknown DefaultStatement: %s " % element.default_type
-                
+                raise ValueError("Unknown DefaultStatement: %s " % element.default_type)
+
         elif isinstance(element, P_AttrList):
-        
             g.obj_dict['attributes'].update(element.attrs)
 
         else:
-            raise ValueError, "Unknown element statement: %r" % element
+            raise ValueError("Unknown element statement: %r" % element)
 
 
-def push_graph_stmt(str, loc, toks):            
-                       
+def push_graph_stmt(str, loc, toks):
     g = pydot.Subgraph('')
     add_elements(g, toks)
     return g
 
 
 def push_subgraph_stmt(str, loc, toks):
-
     g = pydot.Subgraph('')
+
     for e in toks:
-        if len(e)==3:
+        if len(e) == 3:
             e[2].set_name(e[1])
             if e[0] == 'subgraph':
                 e[2].obj_dict['show_keyword'] = True
@@ -253,11 +231,9 @@ def push_subgraph_stmt(str, loc, toks):
 
 
 def push_default_stmt(str, loc, toks):
-
     # The pydot class instances should be marked as
     # default statements to be inherited by actual
     # graphs, nodes and edges.
-    #
     default_type = toks[0][0]
     if len(toks) > 1:
         attrs = toks[1].attrs
@@ -267,90 +243,80 @@ 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: %r " % toks
+        raise ValueError("Unknown default statement: %r " % toks)
 
 
 def push_attr_list(str, loc, toks):
-
     p = P_AttrList(toks)
     return p
 
 
 def get_port(node):
-
-    if len(node)>1:
+    if len(node) > 1:
         if isinstance(node[1], ParseResults):
-            if len(node[1][0])==2:
-                if node[1][0][0]==':':
+            if len(node[1][0]) == 2:
+                if node[1][0][0] == ':':
                     return node[1][0][1]
-                    
     return None
 
-    
-def do_node_ports(node):
 
+def do_node_ports(node):
     node_port = ''
+
     if len(node) > 1:
-        node_port = ''.join( [str(a)+str(b) for a,b in node[1] ] )
+        node_port = ''.join([str(a) + str(b) for a, b in node[1]])
 
     return node_port
 
-    
+
 def push_edge_stmt(str, loc, toks):
-    
     tok_attrs = [a for a in toks if isinstance(a, P_AttrList)]
     attrs = {}
+
     for a in tok_attrs:
         attrs.update(a.attrs)
 
     e = []
 
     if isinstance(toks[0][0], pydot.Graph):
-    
         n_prev = pydot.frozendict(toks[0][0].obj_dict)
-    else:        
-        n_prev = toks[0][0] + do_node_ports( toks[0] )
+    else:
+        n_prev = toks[0][0] + do_node_ports(toks[0])
 
     if isinstance(toks[2][0], ParseResults):
-    
-        n_next_list = [[n.get_name(),] for n in toks[2][0] ]
+        n_next_list = [[n.get_name()] for n in toks[2][0]]
         for n_next in [n for n in n_next_list]:
             n_next_port = do_node_ports(n_next)
-            e.append(pydot.Edge(n_prev, n_next[0]+n_next_port, **attrs))
+            e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs))
 
     elif isinstance(toks[2][0], pydot.Graph):
-    
         e.append(pydot.Edge(n_prev, pydot.frozendict(toks[2][0].obj_dict), **attrs))
 
     elif isinstance(toks[2][0], pydot.Node):
-    
         node = toks[2][0]
-        
+
         if node.get_port() is not None:
             name_port = node.get_name() + ":" + node.get_port()
         else:
             name_port = node.get_name()
-        
+
         e.append(pydot.Edge(n_prev, name_port, **attrs))
 
     elif isinstance(toks[2][0], type('')):
-    
         for n_next in [n for n in tuple(toks)[2::2]]:
-
             if isinstance(n_next, P_AttrList) or not isinstance(n_next[0], type('')):
                 continue
 
-            n_next_port = do_node_ports( n_next )
-            e.append(pydot.Edge(n_prev, n_next[0]+n_next_port, **attrs))
-                
-            n_prev = n_next[0]+n_next_port
-            
+            n_next_port = do_node_ports(n_next)
+            e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs))
+
+            n_prev = n_next[0] + n_next_port
+
     else:
         # UNEXPECTED EDGE TYPE
         pass
-        
-    return e
 
+    return e
 
 
 def push_node_stmt(s, loc, toks):
@@ -359,30 +325,25 @@ def push_node_stmt(s, loc, toks):
         attrs = toks[1].attrs
     else:
         attrs = {}
-        
+
     node_name = toks[0]
     if isinstance(node_name, list) or isinstance(node_name, tuple):
-        if len(node_name)>0:
+        if len(node_name) > 0:
             node_name = node_name[0]
-    
+
     n = pydot.Node(str(node_name), **attrs)
     return n
 
 
-
-    
-    
-
 graphparser = None
 
-def graph_definition():
 
+def graph_definition():
     global graphparser
-    
+
     if not graphparser:
-    
         # punctuation
-        colon  = Literal(":")
+        colon = Literal(":")
         lbrace = Literal("{")
         rbrace = Literal("}")
         lbrack = Literal("[")
@@ -390,142 +351,170 @@ def graph_definition():
         lparen = Literal("(")
         rparen = Literal(")")
         equals = Literal("=")
-        comma  = Literal(",")
-        dot    = Literal(".")
-        slash  = Literal("/")
-        bslash = Literal("\\")
-        star   = Literal("*")
-        semi   = Literal(";")
-        at     = Literal("@")
-        minus  = Literal("-")
-        
+        comma = Literal(",")
+        # dot = Literal(".")
+        # slash = Literal("/")
+        # bslash = Literal("\\")
+        # star = Literal("*")
+        semi = Literal(";")
+        at = Literal("@")
+        minus = Literal("-")
+
         # keywords
-        strict_    = CaselessLiteral("strict")
-        graph_     = CaselessLiteral("graph")
-        digraph_   = CaselessLiteral("digraph")
-        subgraph_  = CaselessLiteral("subgraph")
-        node_      = CaselessLiteral("node")
-        edge_      = CaselessLiteral("edge")
-        
-        
+        strict_ = CaselessLiteral("strict")
+        graph_ = CaselessLiteral("graph")
+        digraph_ = CaselessLiteral("digraph")
+        subgraph_ = CaselessLiteral("subgraph")
+        node_ = CaselessLiteral("node")
+        edge_ = CaselessLiteral("edge")
+
         # token definitions
-        
-        identifier = Word(alphanums + "_." ).setName("identifier")
-        
-        double_quoted_string = QuotedString('"', multiline=True, unquoteResults=False) # dblQuotedString
+        identifier = Word(alphanums + "_.").setName("identifier")
+
+        # dblQuotedString
+        double_quoted_string = QuotedString('"', multiline=True, unquoteResults=False)
 
-        alphastring_ = OneOrMore(CharsNotIn(_noncomma + ' '))
+        noncomma_ = "".join([c for c in printables if c != ","])
+        alphastring_ = OneOrMore(CharsNotIn(noncomma_ + ' '))
 
         def parse_html(s, loc, toks):
             return '<%s>' % ''.join(toks[0])
-            
-        
+
         opener = '<'
         closer = '>'
-        html_text = nestedExpr( opener, closer, 
-            ( CharsNotIn( opener + closer )  ) 
-                ).setParseAction(parse_html).leaveWhitespace()
-
-        ID = ( identifier | html_text | 
-            double_quoted_string | #.setParseAction(strip_quotes) |
-            alphastring_ ).setName("ID")
-            
-        
-        float_number = Combine(Optional(minus) +	
-            OneOrMore(Word(nums + "."))).setName("float_number")
-            
-        righthand_id =  (float_number | ID ).setName("righthand_id")
+        html_text = nestedExpr(
+            opener, closer,
+            (CharsNotIn(opener + closer))
+            ).setParseAction(parse_html).leaveWhitespace()
+
+        ID = (
+            identifier | html_text |
+            double_quoted_string |  # .setParseAction(strip_quotes) |
+            alphastring_
+            ).setName("ID")
+
+        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 = (Group(port_location + Optional(port_angle)) |	
-            Group(port_angle + Optional(port_location))).setName("port")
-            
+
+        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")
+
         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")
-        
+
         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")
-        
-        edge_point << Group( subgraph | graph_stmt | node_id ).setName('edge_point')
-        
-        node_stmt = (node_id + Optional(attr_list) + Optional(semi.suppress())).setName("node_stmt")
-        
+
+        edge_point << Group(subgraph | graph_stmt | node_id).setName('edge_point')
+
+        node_stmt = (
+            node_id + Optional(attr_list) + Optional(semi.suppress())
+            ).setName("node_stmt")
+
         assignment = (ID + equals + righthand_id).setName("assignment")
-        stmt =  (assignment | edge_stmt | attr_stmt | subgraph | graph_stmt | node_stmt).setName("stmt")
+        stmt = (
+            assignment | edge_stmt | attr_stmt |
+            subgraph | graph_stmt | node_stmt
+            ).setName("stmt")
         stmt_list << OneOrMore(stmt + Optional(semi.suppress()))
-        
-        graphparser = OneOrMore( (Optional(strict_) + Group((graph_ | digraph_)) +
-            Optional(ID) + graph_stmt).setResultsName("graph") )
-        
+
+        graphparser = OneOrMore((
+            Optional(strict_) + Group((graph_ | digraph_)) +
+            Optional(ID) + graph_stmt
+            ).setResultsName("graph"))
+
         singleLineComment = Group("//" + restOfLine) | Group("#" + restOfLine)
-        
-        
+
         # actions
-        
         graphparser.ignore(singleLineComment)
         graphparser.ignore(cStyleComment)
-        
+
         assignment.setParseAction(push_attr_list)
         a_list.setParseAction(push_attr_list)
         edge_stmt.setParseAction(push_edge_stmt)
         node_stmt.setParseAction(push_node_stmt)
         attr_stmt.setParseAction(push_default_stmt)
-        
+
         subgraph.setParseAction(push_subgraph_stmt)
         graph_stmt.setParseAction(push_graph_stmt)
         graphparser.setParseAction(push_top_graph_stmt)
-        
-    
+
     return graphparser
 
 
 def parse_dot_data(data):
-
     global top_graphs
-    
+
     top_graphs = list()
 
-    if data.startswith(codecs.BOM_UTF8):
-        data = data.decode( 'utf-8' )
-        
+    if PY3:
+        if isinstance(data, bytes):
+            # this is extremely hackish
+            try:
+                idx = data.index(b'charset') + 7
+                while data[idx] in b' \t\n\r=':
+                    idx += 1
+                fst = idx
+                while data[idx] not in b' \t\n\r];,':
+                    idx += 1
+                charset = data[fst:idx].strip(b'"\'').decode('ascii')
+                data = data.decode(charset)
+            except:
+                data = data.decode('utf-8')
+    else:
+        if data.startswith(codecs.BOM_UTF8):
+            data = data.decode('utf-8')
+
     try:
-    
+
         graphparser = graph_definition()
-        
+
         if pyparsing_version >= '1.2':
             graphparser.parseWithTabs()
-            
+
         tokens = graphparser.parseString(data)
 
         if len(tokens) == 1:
             return tokens[0]
         else:
             return [g for g in tokens]
-        
-    except ParseException, err:
-    
-        print err.line
-        print " "*(err.column-1) + "^"
-        print err
+
+    except ParseException:
+        err = sys.exc_info()[1]
+        print(err.line)
+        print(" " * (err.column - 1) + "^")
+        print(err)
         return None
diff --git a/pydot.py b/pydot.py
index e9bd2a1..c20db18 100644
--- a/pydot.py
+++ b/pydot.py
@@ -17,24 +17,40 @@ Copyright (c) 2005-2011 Ero Carrera <ero.carrera at gmail.com>
 Distributed under MIT license [http://opensource.org/licenses/mit-license.html].
 """
 
-__revision__ = "$LastChangedRevision: 28 $"
+from __future__ import division, print_function
+
 __author__ = 'Ero Carrera'
-__version__ = '1.0.%d' % int( __revision__[21:-2] )
+__version__ = '1.0.29'
 __license__ = 'MIT'
 
 import os
 import re
 import subprocess
+import sys
 import tempfile
 import copy
+
+from operator import itemgetter
+
 try:
     import dot_parser
-except Exception, e:
-    print "Couldn't import dot_parser, loading of dot files will not be possible."
-    
+except Exception:
+    print("Couldn't import dot_parser, loading of dot files will not be possible.")
+
 
+PY3 = not sys.version_info < (3, 0, 0)
 
-GRAPH_ATTRIBUTES = set( ['Damping', 'K', 'URL', 'aspect', 'bb', 'bgcolor',
+if PY3:
+    NULL_SEP = b''
+    basestring = str
+    long = int
+    unicode = str
+else:
+    NULL_SEP = ''
+
+
+GRAPH_ATTRIBUTES = set([
+    'Damping', 'K', 'URL', 'aspect', 'bb', 'bgcolor',
     'center', 'charset', 'clusterrank', 'colorscheme', 'comment', 'compound',
     'concentrate', 'defaultdist', 'dim', 'dimen', 'diredgeconstraints',
     'dpi', 'epsilon', 'esep', 'fontcolor', 'fontname', 'fontnames',
@@ -46,13 +62,15 @@ GRAPH_ATTRIBUTES = set( ['Damping', 'K', 'URL', 'aspect', 'bb', 'bgcolor',
     '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', 
+    'showboxes', 'size', 'smoothing', 'sortv', 'splines', 'start',
     'stylesheet', 'target', 'truecolor', 'viewport', 'voro_margin',
-    # for subgraphs 
-    'rank' ] )
+    # for subgraphs
+    'rank'
+   ])
 
 
-EDGE_ATTRIBUTES = set( ['URL', 'arrowhead', 'arrowsize', 'arrowtail',
+EDGE_ATTRIBUTES = set([
+    'URL', 'arrowhead', 'arrowsize', 'arrowtail',
     'color', 'colorscheme', 'comment', 'constraint', 'decorate', 'dir',
     'edgeURL', 'edgehref', 'edgetarget', 'edgetooltip', 'fontcolor',
     'fontname', 'fontsize', 'headURL', 'headclip', 'headhref', 'headlabel',
@@ -63,10 +81,12 @@ EDGE_ATTRIBUTES = set( ['URL', 'arrowhead', 'arrowsize', 'arrowtail',
     'nojustify', 'penwidth', 'pos', 'samehead', 'sametail', 'showboxes',
     'style', 'tailURL', 'tailclip', 'tailhref', 'taillabel', 'tailport',
     'tailtarget', 'tailtooltip', 'target', 'tooltip', 'weight',
-    'rank' ] )
+    'rank'
+   ])
 
 
-NODE_ATTRIBUTES = set( ['URL', 'color', 'colorscheme', 'comment',
+NODE_ATTRIBUTES = set([
+    'URL', 'color', 'colorscheme', 'comment',
     'distortion', 'fillcolor', 'fixedsize', 'fontcolor', 'fontname',
     'fontsize', 'group', 'height', 'id', 'image', 'imagescale', 'label',
     'labelloc', 'layer', 'margin', 'nojustify', 'orientation', 'penwidth',
@@ -74,14 +94,62 @@ NODE_ATTRIBUTES = set( ['URL', 'color', 'colorscheme', 'comment',
     'shape', 'shapefile', 'showboxes', 'sides', 'skew', 'sortv', 'style',
     'target', 'tooltip', 'vertices', 'width', 'z',
     # The following are attributes dot2tex
-    'texlbl',  'texmode' ] )
+    'texlbl', 'texmode'
+   ])
 
 
-CLUSTER_ATTRIBUTES = set( ['K', 'URL', 'bgcolor', 'color', 'colorscheme',
+CLUSTER_ATTRIBUTES = set([
+    'K', 'URL', 'bgcolor', 'color', 'colorscheme',
     'fillcolor', 'fontcolor', 'fontname', 'fontsize', 'label', 'labeljust',
     'labelloc', 'lheight', 'lp', 'lwidth', 'nojustify', 'pencolor',
-    'penwidth', 'peripheries', 'sortv', 'style', 'target', 'tooltip'] )
-            
+    'penwidth', 'peripheries', 'sortv', 'style', 'target', 'tooltip'
+   ])
+
+
+def is_string_like(obj): # from John Hunter, types-free version
+    """Check if obj is string."""
+    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.
+    mode : str
+        The mode of the file to be opened.
+
+    Returns
+    -------
+    fobj : file object
+        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.
+
+    """
+    if is_string_like(fname):
+        fobj = open(fname, mode)
+        close = True
+    elif hasattr(fname, 'write'):
+        # fname is a file-like object, perhaps a StringIO (for example)
+        fobj = fname
+        close = False
+    else:
+        # assume it is a file descriptor
+        fobj = os.fdopen(fname, mode)
+        close = False
+    return fobj, close
+
 
 #
 # Extented version of ASPN's Python Cookbook Recipe:
@@ -92,7 +160,7 @@ CLUSTER_ATTRIBUTES = set( ['K', 'URL', 'bgcolor', 'color', 'colorscheme',
 #
 class frozendict(dict):
     def _blocked_attribute(obj):
-        raise AttributeError, "A frozendict cannot be modified."
+        raise AttributeError("A frozendict cannot be modified.")
     _blocked_attribute = property(_blocked_attribute)
 
     __delitem__ = __setitem__ = clear = _blocked_attribute
@@ -105,7 +173,7 @@ class frozendict(dict):
         for arg in args:
             if isinstance(arg, dict):
                 arg = copy.copy(arg)
-                for k, v in arg.iteritems():
+                for k, v in arg.items():
                     if isinstance(v, frozendict):
                         arg[k] = v
                     elif isinstance(v, dict):
@@ -114,13 +182,13 @@ class frozendict(dict):
                         v_ = list()
                         for elm in v:
                             if isinstance(elm, dict):
-                                v_.append( frozendict(elm) )
+                                v_.append(frozendict(elm))
                             else:
-                                v_.append( elm )
+                                v_.append(elm)
                         arg[k] = tuple(v_)
-                args_.append( arg )
+                args_.append(arg)
             else:
-                args_.append( arg )
+                args_.append(arg)
 
         dict.__init__(new, *args_, **kw)
         return new
@@ -132,7 +200,7 @@ class frozendict(dict):
         try:
             return self._cached_hash
         except AttributeError:
-            h = self._cached_hash = hash(tuple(sorted(self.iteritems())))
+            h = self._cached_hash = hash(tuple(sorted(self.items())))
             return h
 
     def __repr__(self):
@@ -142,23 +210,25 @@ class frozendict(dict):
 dot_keywords = ['graph', 'subgraph', 'digraph', 'node', 'edge', 'strict']
 
 id_re_alpha_nums = re.compile('^[_a-zA-Z][a-zA-Z0-9_,]*$', re.UNICODE)
-id_re_alpha_nums_with_ports = re.compile('^[_a-zA-Z][a-zA-Z0-9_,:\"]*[a-zA-Z0-9_,\"]+$', re.UNICODE)
+id_re_alpha_nums_with_ports = re.compile(
+    '^[_a-zA-Z][a-zA-Z0-9_,:\"]*[a-zA-Z0-9_,\"]+$', re.UNICODE
+    )
 id_re_num = re.compile('^[0-9,]+$', re.UNICODE)
 id_re_with_port = re.compile('^([^:]*):([^:]*)$', re.UNICODE)
-id_re_dbl_quoted = re.compile('^\".*\"$', re.S|re.UNICODE)
-id_re_html = re.compile('^<.*>$', re.S|re.UNICODE)
+id_re_dbl_quoted = re.compile('^\".*\"$', re.S | re.UNICODE)
+id_re_html = re.compile('^<.*>$', re.S | re.UNICODE)
 
 
-def needs_quotes( s ):
+def needs_quotes(s):
     """Checks whether a string is a dot language ID.
-    
+
     It will check whether the string is solely composed
     by the characters allowed in an ID or not.
     If the string is one of the reserved keywords it will
     need quotes too but the user will need to add them
     manually.
     """
-    
+
     # If the name is a reserved keyword it will need quotes but pydot
     # can't tell when it's being used as a keyword or when it's simply
     # a name. Hence the user needs to supply the quotes when an element
@@ -168,11 +238,14 @@ def needs_quotes( s ):
     if s in dot_keywords:
         return False
 
-    chars = [ord(c) for c in s if ord(c)>0x7f or ord(c)==0]
+    chars = [ord(c) for c in s if ord(c) > 0x7f or ord(c) == 0]
     if chars and not id_re_dbl_quoted.match(s) and not id_re_html.match(s):
         return True
-        
-    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
 
@@ -184,109 +257,109 @@ def needs_quotes( s ):
 
 
 def quote_if_necessary(s):
+    # Older versions of graphviz throws a syntax error for empty values without
+    # quotes, e.g. [label=]
+    if s == '':
+        return '""'
 
... 2488 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pydot.git



More information about the Python-modules-commits mailing list