Index: third_party/pylint/pyreverse/writer.py |
diff --git a/third_party/pylint/pyreverse/writer.py b/third_party/pylint/pyreverse/writer.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6dbfc2658c5690c26d288280347049589b1ae633 |
--- /dev/null |
+++ b/third_party/pylint/pyreverse/writer.py |
@@ -0,0 +1,196 @@ |
+# -*- coding: utf-8 -*- |
+# Copyright (c) 2008-2010 LOGILAB S.A. (Paris, FRANCE). |
+# http://www.logilab.fr/ -- mailto:contact@logilab.fr |
+# |
+# This program is free software; you can redistribute it and/or modify it under |
+# the terms of the GNU General Public License as published by the Free Software |
+# Foundation; either version 2 of the License, or (at your option) any later |
+# version. |
+# |
+# This program is distributed in the hope that it will be useful, but WITHOUT |
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
+# |
+# You should have received a copy of the GNU General Public License along with |
+# this program; if not, write to the Free Software Foundation, Inc., |
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
+""" |
+Utilities for creating VCG and Dot diagrams. |
+""" |
+ |
+from logilab.common.vcgutils import VCGPrinter |
+from logilab.common.graph import DotBackend |
+ |
+from pylint.pyreverse.utils import is_exception |
+ |
+class DiagramWriter: |
+ """base class for writing project diagrams |
+ """ |
+ def __init__(self, config, styles): |
+ self.config = config |
+ self.pkg_edges, self.inh_edges, self.imp_edges, self.ass_edges = styles |
+ self.printer = None # defined in set_printer |
+ |
+ def write(self, diadefs): |
+ """write files for <project> according to <diadefs> |
+ """ |
+ for diagram in diadefs: |
+ basename = diagram.title.strip().replace(' ', '_') |
+ file_name = '%s.%s' % (basename, self.config.output_format) |
+ self.set_printer(file_name, basename) |
+ if diagram.TYPE == 'class': |
+ self.write_classes(diagram) |
+ else: |
+ self.write_packages(diagram) |
+ self.close_graph() |
+ |
+ def write_packages(self, diagram): |
+ """write a package diagram""" |
+ for obj in diagram.modules(): |
+ label = self.get_title(obj) |
+ self.printer.emit_node(obj.fig_id, label=label, shape='box') |
+ # package dependencies |
+ for rel in diagram.relationships.get('depends', ()): |
+ self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id, |
+ **self.pkg_edges) |
+ |
+ def write_classes(self, diagram): |
+ """write a class diagram""" |
+ for obj in diagram.objects: |
+ self.printer.emit_node(obj.fig_id, **self.get_values(obj) ) |
+ # inheritance links |
+ for rel in diagram.relationships.get('specialization', ()): |
+ self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id, |
+ **self.inh_edges) |
+ # implementation links |
+ for rel in diagram.relationships.get('implements', ()): |
+ self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id, |
+ **self.imp_edges) |
+ # generate associations |
+ for rel in diagram.relationships.get('association', ()): |
+ self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id, |
+ label=rel.name, **self.ass_edges) |
+ |
+ def set_printer(self, file_name, basename): |
+ """set printer""" |
+ raise NotImplementedError |
+ |
+ def get_title(self, obj): |
+ """get project title""" |
+ raise NotImplementedError |
+ |
+ def get_values(self, obj): |
+ """get label and shape for classes.""" |
+ raise NotImplementedError |
+ |
+ def close_graph(self): |
+ """finalize the graph""" |
+ raise NotImplementedError |
+ |
+ |
+class DotWriter(DiagramWriter): |
+ """write dot graphs from a diagram definition and a project |
+ """ |
+ |
+ def __init__(self, config): |
+ styles = [dict(arrowtail='none', arrowhead="open"), |
+ dict(arrowtail = "none", arrowhead='empty'), |
+ dict(arrowtail="node", arrowhead='empty', style='dashed'), |
+ dict(fontcolor='green', arrowtail='none', |
+ arrowhead='diamond', style='solid') ] |
+ DiagramWriter.__init__(self, config, styles) |
+ |
+ def set_printer(self, file_name, basename): |
+ """initialize DotWriter and add options for layout. |
+ """ |
+ layout = dict(rankdir="BT") |
+ self.printer = DotBackend(basename, additionnal_param=layout) |
+ self.file_name = file_name |
+ |
+ def get_title(self, obj): |
+ """get project title""" |
+ return obj.title |
+ |
+ def get_values(self, obj): |
+ """get label and shape for classes. |
+ |
+ The label contains all attributes and methods |
+ """ |
+ label = obj.title |
+ if obj.shape == 'interface': |
+ label = "«interface»\\n%s" % label |
+ if not self.config.only_classnames: |
+ label = "%s|%s\l|" % (label, r"\l".join(obj.attrs) ) |
+ for func in obj.methods: |
+ label = r'%s%s()\l' % (label, func.name) |
+ label = '{%s}' % label |
+ if is_exception(obj.node): |
+ return dict(fontcolor="red", label=label, shape="record") |
+ return dict(label=label, shape="record") |
+ |
+ def close_graph(self): |
+ """print the dot graph into <file_name>""" |
+ self.printer.generate(self.file_name) |
+ |
+ |
+class VCGWriter(DiagramWriter): |
+ """write vcg graphs from a diagram definition and a project |
+ """ |
+ def __init__(self, config): |
+ styles = [dict(arrowstyle='solid', backarrowstyle='none', |
+ backarrowsize=0), |
+ dict(arrowstyle='solid', backarrowstyle='none', |
+ backarrowsize=10), |
+ dict(arrowstyle='solid', backarrowstyle='none', |
+ linestyle='dotted', backarrowsize=10), |
+ dict(arrowstyle='solid', backarrowstyle='none', |
+ textcolor='green') ] |
+ DiagramWriter.__init__(self, config, styles) |
+ |
+ def set_printer(self, file_name, basename): |
+ """initialize VCGWriter for a UML graph""" |
+ self.graph_file = open(file_name, 'w+') |
+ self.printer = VCGPrinter(self.graph_file) |
+ self.printer.open_graph(title=basename, layoutalgorithm='dfs', |
+ late_edge_labels='yes', port_sharing='no', |
+ manhattan_edges='yes') |
+ self.printer.emit_node = self.printer.node |
+ self.printer.emit_edge = self.printer.edge |
+ |
+ def get_title(self, obj): |
+ """get project title in vcg format""" |
+ return r'\fb%s\fn' % obj.title |
+ |
+ def get_values(self, obj): |
+ """get label and shape for classes. |
+ |
+ The label contains all attributes and methods |
+ """ |
+ if is_exception(obj.node): |
+ label = r'\fb\f09%s\fn' % obj.title |
+ else: |
+ label = r'\fb%s\fn' % obj.title |
+ if obj.shape == 'interface': |
+ shape = 'ellipse' |
+ else: |
+ shape = 'box' |
+ if not self.config.only_classnames: |
+ attrs = obj.attrs |
+ methods = [func.name for func in obj.methods] |
+ # box width for UML like diagram |
+ maxlen = max(len(name) for name in [obj.title] + methods + attrs) |
+ line = "_" * (maxlen + 2) |
+ label = r'%s\n\f%s' % (label, line) |
+ for attr in attrs: |
+ label = r'%s\n\f08%s' % (label, attr) |
+ if attrs: |
+ label = r'%s\n\f%s' % (label, line) |
+ for func in methods: |
+ label = r'%s\n\f10%s()' % (label, func) |
+ return dict(label=label, shape=shape) |
+ |
+ def close_graph(self): |
+ """close graph and file""" |
+ self.printer.close_graph() |
+ self.graph_file.close() |
+ |