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 |
|