Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / pylint / graph.py @ 745

History | View | Annotate | Download (6.61 KB)

1
# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
2
# This program is free software; you can redistribute it and/or modify it under
3
# the terms of the GNU General Public License as published by the Free Software
4
# Foundation; either version 2 of the License, or (at your option) any later
5
# version.
6
#
7
# This program is distributed in the hope that it will be useful, but WITHOUT
8
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
10
#
11
# You should have received a copy of the GNU General Public License along with
12
# this program; if not, write to the Free Software Foundation, Inc.,
13
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14

    
15
# This file was copied from logilab-common with the same license:
16
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
17
"""Graph manipulation utilities.
18

19
(dot generation adapted from pypy/translator/tool/make_dot.py)
20
"""
21

    
22
import os.path as osp
23
import os
24
import sys
25
import tempfile
26
import codecs
27

    
28
def target_info_from_filename(filename):
29
    """Transforms /some/path/foo.png into ('/some/path', 'foo.png', 'png')."""
30
    basename = osp.basename(filename)
31
    storedir = osp.dirname(osp.abspath(filename))
32
    target = filename.split('.')[-1]
33
    return storedir, basename, target
34

    
35

    
36
class DotBackend(object):
37
    """Dot File backend."""
38
    def __init__(self, graphname, rankdir=None, size=None, ratio=None,
39
                 charset='utf-8', renderer='dot', additional_param=None):
40
        if additional_param is None:
41
            additional_param = {}
42
        self.graphname = graphname
43
        self.renderer = renderer
44
        self.lines = []
45
        self._source = None
46
        self.emit("digraph %s {" % normalize_node_id(graphname))
47
        if rankdir:
48
            self.emit('rankdir=%s' % rankdir)
49
        if ratio:
50
            self.emit('ratio=%s' % ratio)
51
        if size:
52
            self.emit('size="%s"' % size)
53
        if charset:
54
            assert charset.lower() in ('utf-8', 'iso-8859-1', 'latin1'), \
55
                   'unsupported charset %s' % charset
56
            self.emit('charset="%s"' % charset)
57
        for param in additional_param.items():
58
            self.emit('='.join(param))
59

    
60
    def get_source(self):
61
        """returns self._source"""
62
        if self._source is None:
63
            self.emit("}\n")
64
            self._source = '\n'.join(self.lines)
65
            del self.lines
66
        return self._source
67

    
68
    source = property(get_source)
69

    
70
    def generate(self, outputfile=None, dotfile=None, mapfile=None):
71
        """Generates a graph file.
72

73
        :param outputfile: filename and path [defaults to graphname.png]
74
        :param dotfile: filename and path [defaults to graphname.dot]
75

76
        :rtype: str
77
        :return: a path to the generated file
78
        """
79
        import subprocess # introduced in py 2.4
80
        name = self.graphname
81
        if not dotfile:
82
            # if 'outputfile' is a dot file use it as 'dotfile'
83
            if outputfile and outputfile.endswith(".dot"):
84
                dotfile = outputfile
85
            else:
86
                dotfile = '%s.dot' % name
87
        if outputfile is not None:
88
            storedir, _, target = target_info_from_filename(outputfile)
89
            if target != "dot":
90
                pdot, dot_sourcepath = tempfile.mkstemp(".dot", name)
91
                os.close(pdot)
92
            else:
93
                dot_sourcepath = osp.join(storedir, dotfile)
94
        else:
95
            target = 'png'
96
            pdot, dot_sourcepath = tempfile.mkstemp(".dot", name)
97
            ppng, outputfile = tempfile.mkstemp(".png", name)
98
            os.close(pdot)
99
            os.close(ppng)
100
        pdot = codecs.open(dot_sourcepath, 'w', encoding='utf8')
101
        pdot.write(self.source)
102
        pdot.close()
103
        if target != 'dot':
104
            use_shell = sys.platform == 'win32'
105
            if mapfile:
106
                subprocess.call([self.renderer, '-Tcmapx', '-o',
107
                                 mapfile, '-T', target, dot_sourcepath,
108
                                 '-o', outputfile],
109
                                shell=use_shell)
110
            else:
111
                subprocess.call([self.renderer, '-T', target,
112
                                 dot_sourcepath, '-o', outputfile],
113
                                shell=use_shell)
114
            os.unlink(dot_sourcepath)
115
        return outputfile
116

    
117
    def emit(self, line):
118
        """Adds <line> to final output."""
119
        self.lines.append(line)
120

    
121
    def emit_edge(self, name1, name2, **props):
122
        """emit an edge from <name1> to <name2>.
123
        edge properties: see http://www.graphviz.org/doc/info/attrs.html
124
        """
125
        attrs = ['%s="%s"' % (prop, value) for prop, value in props.items()]
126
        n_from, n_to = normalize_node_id(name1), normalize_node_id(name2)
127
        self.emit('%s -> %s [%s];' % (n_from, n_to, ', '.join(sorted(attrs))))
128

    
129
    def emit_node(self, name, **props):
130
        """emit a node with given properties.
131
        node properties: see http://www.graphviz.org/doc/info/attrs.html
132
        """
133
        attrs = ['%s="%s"' % (prop, value) for prop, value in props.items()]
134
        self.emit('%s [%s];' % (normalize_node_id(name), ', '.join(sorted(attrs))))
135

    
136
def normalize_node_id(nid):
137
    """Returns a suitable DOT node id for `nid`."""
138
    return '"%s"' % nid
139

    
140
def get_cycles(graph_dict, vertices=None):
141
    '''given a dictionary representing an ordered graph (i.e. key are vertices
142
    and values is a list of destination vertices representing edges), return a
143
    list of detected cycles
144
    '''
145
    if not graph_dict:
146
        return ()
147
    result = []
148
    if vertices is None:
149
        vertices = graph_dict.keys()
150
    for vertice in vertices:
151
        _get_cycles(graph_dict, [], set(), result, vertice)
152
    return result
153

    
154
def _get_cycles(graph_dict, path, visited, result, vertice):
155
    """recursive function doing the real work for get_cycles"""
156
    if vertice in path:
157
        cycle = [vertice]
158
        for node in path[::-1]:
159
            if node == vertice:
160
                break
161
            cycle.insert(0, node)
162
        # make a canonical representation
163
        start_from = min(cycle)
164
        index = cycle.index(start_from)
165
        cycle = cycle[index:] + cycle[0:index]
166
        # append it to result if not already in
167
        if cycle not in result:
168
            result.append(cycle)
169
        return
170
    path.append(vertice)
171
    try:
172
        for node in graph_dict[vertice]:
173
            # don't check already visited nodes again
174
            if node not in visited:
175
                _get_cycles(graph_dict, path, visited, result, node)
176
                visited.add(node)
177
    except KeyError:
178
        pass
179
    path.pop()