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 / pyreverse / writer.py @ 745

History | View | Annotate | Download (7.67 KB)

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

    
19
from pylint.pyreverse.utils import is_exception
20
from pylint.pyreverse.vcgutils import VCGPrinter
21
from pylint.graph import DotBackend
22

    
23
class DiagramWriter(object):
24
    """base class for writing project diagrams
25
    """
26
    def __init__(self, config, styles):
27
        self.config = config
28
        self.pkg_edges, self.inh_edges, self.imp_edges, self.ass_edges = styles
29
        self.printer = None # defined in set_printer
30

    
31
    def write(self, diadefs):
32
        """write files for <project> according to <diadefs>
33
        """
34
        for diagram in diadefs:
35
            basename = diagram.title.strip().replace(' ', '_')
36
            file_name = '%s.%s' % (basename, self.config.output_format)
37
            self.set_printer(file_name, basename)
38
            if diagram.TYPE == 'class':
39
                self.write_classes(diagram)
40
            else:
41
                self.write_packages(diagram)
42
            self.close_graph()
43

    
44
    def write_packages(self, diagram):
45
        """write a package diagram"""
46
        # sorted to get predictable (hence testable) results
47
        for i, obj in enumerate(sorted(diagram.modules(), key=lambda x: x.title)):
48
            self.printer.emit_node(i, label=self.get_title(obj), shape='box')
49
            obj.fig_id = i
50
        # package dependencies
51
        for rel in diagram.get_relationships('depends'):
52
            self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
53
                                   **self.pkg_edges)
54

    
55
    def write_classes(self, diagram):
56
        """write a class diagram"""
57
        # sorted to get predictable (hence testable) results
58
        for i, obj in enumerate(sorted(diagram.objects, key=lambda x: x.title)):
59
            self.printer.emit_node(i, **self.get_values(obj))
60
            obj.fig_id = i
61
        # inheritance links
62
        for rel in diagram.get_relationships('specialization'):
63
            self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
64
                                   **self.inh_edges)
65
        # implementation links
66
        for rel in diagram.get_relationships('implements'):
67
            self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
68
                                   **self.imp_edges)
69
        # generate associations
70
        for rel in diagram.get_relationships('association'):
71
            self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
72
                                   label=rel.name, **self.ass_edges)
73

    
74
    def set_printer(self, file_name, basename):
75
        """set printer"""
76
        raise NotImplementedError
77

    
78
    def get_title(self, obj):
79
        """get project title"""
80
        raise NotImplementedError
81

    
82
    def get_values(self, obj):
83
        """get label and shape for classes."""
84
        raise NotImplementedError
85

    
86
    def close_graph(self):
87
        """finalize the graph"""
88
        raise NotImplementedError
89

    
90

    
91
class DotWriter(DiagramWriter):
92
    """write dot graphs from a diagram definition and a project
93
    """
94

    
95
    def __init__(self, config):
96
        styles = [dict(arrowtail='none', arrowhead="open"),
97
                  dict(arrowtail='none', arrowhead='empty'),
98
                  dict(arrowtail='node', arrowhead='empty', style='dashed'),
99
                  dict(fontcolor='green', arrowtail='none',
100
                       arrowhead='diamond', style='solid'),
101
                 ]
102
        DiagramWriter.__init__(self, config, styles)
103

    
104
    def set_printer(self, file_name, basename):
105
        """initialize DotWriter and add options for layout.
106
        """
107
        layout = dict(rankdir="BT")
108
        self.printer = DotBackend(basename, additional_param=layout)
109
        self.file_name = file_name
110

    
111
    def get_title(self, obj):
112
        """get project title"""
113
        return obj.title
114

    
115
    def get_values(self, obj):
116
        """get label and shape for classes.
117

118
        The label contains all attributes and methods
119
        """
120
        label = obj.title
121
        if obj.shape == 'interface':
122
            label = u'«interface»\\n%s' % label
123
        if not self.config.only_classnames:
124
            label = r'%s|%s\l|' % (label, r'\l'.join(obj.attrs))
125
            for func in obj.methods:
126
                label = r'%s%s()\l' % (label, func.name)
127
            label = '{%s}' % label
128
        if is_exception(obj.node):
129
            return dict(fontcolor='red', label=label, shape='record')
130
        return dict(label=label, shape='record')
131

    
132
    def close_graph(self):
133
        """print the dot graph into <file_name>"""
134
        self.printer.generate(self.file_name)
135

    
136

    
137
class VCGWriter(DiagramWriter):
138
    """write vcg graphs from a diagram definition and a project
139
    """
140
    def __init__(self, config):
141
        styles = [dict(arrowstyle='solid', backarrowstyle='none',
142
                       backarrowsize=0),
143
                  dict(arrowstyle='solid', backarrowstyle='none',
144
                       backarrowsize=10),
145
                  dict(arrowstyle='solid', backarrowstyle='none',
146
                       linestyle='dotted', backarrowsize=10),
147
                  dict(arrowstyle='solid', backarrowstyle='none',
148
                       textcolor='green'),
149
                 ]
150
        DiagramWriter.__init__(self, config, styles)
151

    
152
    def set_printer(self, file_name, basename):
153
        """initialize VCGWriter for a UML graph"""
154
        self.graph_file = open(file_name, 'w+')
155
        self.printer = VCGPrinter(self.graph_file)
156
        self.printer.open_graph(title=basename, layoutalgorithm='dfs',
157
                                late_edge_labels='yes', port_sharing='no',
158
                                manhattan_edges='yes')
159
        self.printer.emit_node = self.printer.node
160
        self.printer.emit_edge = self.printer.edge
161

    
162
    def get_title(self, obj):
163
        """get project title in vcg format"""
164
        return r'\fb%s\fn' % obj.title
165

    
166
    def get_values(self, obj):
167
        """get label and shape for classes.
168

169
        The label contains all attributes and methods
170
        """
171
        if is_exception(obj.node):
172
            label = r'\fb\f09%s\fn' % obj.title
173
        else:
174
            label = r'\fb%s\fn' % obj.title
175
        if obj.shape == 'interface':
176
            shape = 'ellipse'
177
        else:
178
            shape = 'box'
179
        if not self.config.only_classnames:
180
            attrs = obj.attrs
181
            methods = [func.name for func in obj.methods]
182
            # box width for UML like diagram
183
            maxlen = max(len(name) for name in [obj.title] + methods + attrs)
184
            line = '_' * (maxlen + 2)
185
            label = r'%s\n\f%s' % (label, line)
186
            for attr in attrs:
187
                label = r'%s\n\f08%s' % (label, attr)
188
            if attrs:
189
                label = r'%s\n\f%s' % (label, line)
190
            for func in methods:
191
                label = r'%s\n\f10%s()' % (label, func)
192
        return dict(label=label, shape=shape)
193

    
194
    def close_graph(self):
195
        """close graph and file"""
196
        self.printer.close_graph()
197
        self.graph_file.close()
198