Index: third_party/logilab/common/vcgutils.py |
diff --git a/third_party/logilab/common/vcgutils.py b/third_party/logilab/common/vcgutils.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9cd2acda0cd732d61509cfd78b7db400a5e82273 |
--- /dev/null |
+++ b/third_party/logilab/common/vcgutils.py |
@@ -0,0 +1,216 @@ |
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
+# |
+# This file is part of logilab-common. |
+# |
+# logilab-common is free software: you can redistribute it and/or modify it under |
+# the terms of the GNU Lesser General Public License as published by the Free |
+# Software Foundation, either version 2.1 of the License, or (at your option) any |
+# later version. |
+# |
+# logilab-common 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 Lesser General Public License for more |
+# details. |
+# |
+# You should have received a copy of the GNU Lesser General Public License along |
+# with logilab-common. If not, see <http://www.gnu.org/licenses/>. |
+"""Functions to generate files readable with Georg Sander's vcg |
+(Visualization of Compiler Graphs). |
+ |
+You can download vcg at http://rw4.cs.uni-sb.de/~sander/html/gshome.html |
+Note that vcg exists as a debian package. |
+ |
+See vcg's documentation for explanation about the different values that |
+maybe used for the functions parameters. |
+ |
+ |
+ |
+ |
+""" |
+__docformat__ = "restructuredtext en" |
+ |
+import string |
+ |
+ATTRS_VAL = { |
+ 'algos': ('dfs', 'tree', 'minbackward', |
+ 'left_to_right', 'right_to_left', |
+ 'top_to_bottom', 'bottom_to_top', |
+ 'maxdepth', 'maxdepthslow', 'mindepth', 'mindepthslow', |
+ 'mindegree', 'minindegree', 'minoutdegree', |
+ 'maxdegree', 'maxindegree', 'maxoutdegree'), |
+ 'booleans': ('yes', 'no'), |
+ 'colors': ('black', 'white', 'blue', 'red', 'green', 'yellow', |
+ 'magenta', 'lightgrey', |
+ 'cyan', 'darkgrey', 'darkblue', 'darkred', 'darkgreen', |
+ 'darkyellow', 'darkmagenta', 'darkcyan', 'gold', |
+ 'lightblue', 'lightred', 'lightgreen', 'lightyellow', |
+ 'lightmagenta', 'lightcyan', 'lilac', 'turquoise', |
+ 'aquamarine', 'khaki', 'purple', 'yellowgreen', 'pink', |
+ 'orange', 'orchid'), |
+ 'shapes': ('box', 'ellipse', 'rhomb', 'triangle'), |
+ 'textmodes': ('center', 'left_justify', 'right_justify'), |
+ 'arrowstyles': ('solid', 'line', 'none'), |
+ 'linestyles': ('continuous', 'dashed', 'dotted', 'invisible'), |
+ } |
+ |
+# meaning of possible values: |
+# O -> string |
+# 1 -> int |
+# list -> value in list |
+GRAPH_ATTRS = { |
+ 'title': 0, |
+ 'label': 0, |
+ 'color': ATTRS_VAL['colors'], |
+ 'textcolor': ATTRS_VAL['colors'], |
+ 'bordercolor': ATTRS_VAL['colors'], |
+ 'width': 1, |
+ 'height': 1, |
+ 'borderwidth': 1, |
+ 'textmode': ATTRS_VAL['textmodes'], |
+ 'shape': ATTRS_VAL['shapes'], |
+ 'shrink': 1, |
+ 'stretch': 1, |
+ 'orientation': ATTRS_VAL['algos'], |
+ 'vertical_order': 1, |
+ 'horizontal_order': 1, |
+ 'xspace': 1, |
+ 'yspace': 1, |
+ 'layoutalgorithm': ATTRS_VAL['algos'], |
+ 'late_edge_labels': ATTRS_VAL['booleans'], |
+ 'display_edge_labels': ATTRS_VAL['booleans'], |
+ 'dirty_edge_labels': ATTRS_VAL['booleans'], |
+ 'finetuning': ATTRS_VAL['booleans'], |
+ 'manhattan_edges': ATTRS_VAL['booleans'], |
+ 'smanhattan_edges': ATTRS_VAL['booleans'], |
+ 'port_sharing': ATTRS_VAL['booleans'], |
+ 'edges': ATTRS_VAL['booleans'], |
+ 'nodes': ATTRS_VAL['booleans'], |
+ 'splines': ATTRS_VAL['booleans'], |
+ } |
+NODE_ATTRS = { |
+ 'title': 0, |
+ 'label': 0, |
+ 'color': ATTRS_VAL['colors'], |
+ 'textcolor': ATTRS_VAL['colors'], |
+ 'bordercolor': ATTRS_VAL['colors'], |
+ 'width': 1, |
+ 'height': 1, |
+ 'borderwidth': 1, |
+ 'textmode': ATTRS_VAL['textmodes'], |
+ 'shape': ATTRS_VAL['shapes'], |
+ 'shrink': 1, |
+ 'stretch': 1, |
+ 'vertical_order': 1, |
+ 'horizontal_order': 1, |
+ } |
+EDGE_ATTRS = { |
+ 'sourcename': 0, |
+ 'targetname': 0, |
+ 'label': 0, |
+ 'linestyle': ATTRS_VAL['linestyles'], |
+ 'class': 1, |
+ 'thickness': 0, |
+ 'color': ATTRS_VAL['colors'], |
+ 'textcolor': ATTRS_VAL['colors'], |
+ 'arrowcolor': ATTRS_VAL['colors'], |
+ 'backarrowcolor': ATTRS_VAL['colors'], |
+ 'arrowsize': 1, |
+ 'backarrowsize': 1, |
+ 'arrowstyle': ATTRS_VAL['arrowstyles'], |
+ 'backarrowstyle': ATTRS_VAL['arrowstyles'], |
+ 'textmode': ATTRS_VAL['textmodes'], |
+ 'priority': 1, |
+ 'anchor': 1, |
+ 'horizontal_order': 1, |
+ } |
+ |
+ |
+# Misc utilities ############################################################### |
+ |
+def latin_to_vcg(st): |
+ """Convert latin characters using vcg escape sequence. |
+ """ |
+ for char in st: |
+ if char not in string.ascii_letters: |
+ try: |
+ num = ord(char) |
+ if num >= 192: |
+ st = st.replace(char, r'\fi%d'%ord(char)) |
+ except: |
+ pass |
+ return st |
+ |
+ |
+class VCGPrinter: |
+ """A vcg graph writer. |
+ """ |
+ |
+ def __init__(self, output_stream): |
+ self._stream = output_stream |
+ self._indent = '' |
+ |
+ def open_graph(self, **args): |
+ """open a vcg graph |
+ """ |
+ self._stream.write('%sgraph:{\n'%self._indent) |
+ self._inc_indent() |
+ self._write_attributes(GRAPH_ATTRS, **args) |
+ |
+ def close_graph(self): |
+ """close a vcg graph |
+ """ |
+ self._dec_indent() |
+ self._stream.write('%s}\n'%self._indent) |
+ |
+ |
+ def node(self, title, **args): |
+ """draw a node |
+ """ |
+ self._stream.write('%snode: {title:"%s"' % (self._indent, title)) |
+ self._write_attributes(NODE_ATTRS, **args) |
+ self._stream.write('}\n') |
+ |
+ |
+ def edge(self, from_node, to_node, edge_type='', **args): |
+ """draw an edge from a node to another. |
+ """ |
+ self._stream.write( |
+ '%s%sedge: {sourcename:"%s" targetname:"%s"' % ( |
+ self._indent, edge_type, from_node, to_node)) |
+ self._write_attributes(EDGE_ATTRS, **args) |
+ self._stream.write('}\n') |
+ |
+ |
+ # private ################################################################## |
+ |
+ def _write_attributes(self, attributes_dict, **args): |
+ """write graph, node or edge attributes |
+ """ |
+ for key, value in args.items(): |
+ try: |
+ _type = attributes_dict[key] |
+ except KeyError: |
+ raise Exception('''no such attribute %s |
+possible attributes are %s''' % (key, attributes_dict.keys())) |
+ |
+ if not _type: |
+ self._stream.write('%s%s:"%s"\n' % (self._indent, key, value)) |
+ elif _type == 1: |
+ self._stream.write('%s%s:%s\n' % (self._indent, key, |
+ int(value))) |
+ elif value in _type: |
+ self._stream.write('%s%s:%s\n' % (self._indent, key, value)) |
+ else: |
+ raise Exception('''value %s isn\'t correct for attribute %s |
+correct values are %s''' % (value, key, _type)) |
+ |
+ def _inc_indent(self): |
+ """increment indentation |
+ """ |
+ self._indent = ' %s' % self._indent |
+ |
+ def _dec_indent(self): |
+ """decrement indentation |
+ """ |
+ self._indent = self._indent[:-2] |