From a9b7535b7bc7be130d8f1968a1de640118c4b684 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Fri, 23 Oct 2009 19:11:58 +0200 Subject: Copyrightify --- grapher.py | 283 ------------------------------------------------------- umlpy.py | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 311 insertions(+), 283 deletions(-) delete mode 100644 grapher.py create mode 100644 umlpy.py diff --git a/grapher.py b/grapher.py deleted file mode 100644 index 65caf43..0000000 --- a/grapher.py +++ /dev/null @@ -1,283 +0,0 @@ -import epydoc.docparser -import epydoc.docstringparser -import epydoc.apidoc - -import gv - -import sys -import os -import re - -from optparse import OptionParser - -parser = OptionParser() -parser.add_option("-v", dest = "debug", action = "store_true", - default = False, - help = "enables debug output") -parser.add_option("-e", "--exclude", dest = "excludes", action = "append", - default = [], - help = "classes matching this regexp will be excluded \ - from display") -parser.add_option("-i", "--include", dest = "includes", action = "append", - default = [], - help = "classes matching this regexp will be included \ - in display even if they were excluded by exclude \ - regexps") -parser.add_option("-p", "--prefix", dest = "prefix", action = "store", - default = "", - help = "prefix which will be stripped of class names") -parser.add_option("-f", "--force", dest = "forces", action = "append", - default = [], - help = "classes matching this regexp will be forced into \ - display") -parser.add_option("--all-methods", dest = "all_methods", - action = "store_true", default = False, - help = "shows all methods") -parser.add_option("--all-properties", dest = "all_properties", - action = "store_true", default = False, - help = "shows all properties") -parser.add_option("--no-method", dest = "no_method", - action = "store_true", default = False, - help = "shows no method") -parser.add_option("--no-property", dest = "no_property", - action = "store_true", default = False, - help = "shows no property") -parser.add_option("-o", "--output", dest = "output", action = "store", - default = "uml.png", - help = "output file") - -(options, args) = parser.parse_args () - -excludes = reduce (lambda x, y: x + y, - map (lambda s: s.split(","), options.excludes), []) -includes = reduce (lambda x, y: x + y, - map (lambda s: s.split(","), options.includes), []) -forces = reduce (lambda x, y: x + y, - map (lambda s: s.split(","), options.forces), []) -prefix = options.prefix -all_methods = options.all_methods -all_properties = options.all_properties -no_method = options.no_method -no_property = options.no_property -output = options.output - -print "Settings" -print "--------" -print "Output file :", output -print "Prefix :", prefix -print "Show all methods :", all_methods -print "Show all properties :", all_properties -print "Show no method :", no_method -print "Show no propertie :", no_property -print "Excludes :", excludes -print "Includes :", includes -print "Forces :", forces - -excludes = [re.compile (exp) - for exp in excludes] -includes = [re.compile (exp) - for exp in includes] -forces = [re.compile (exp) - for exp in forces] - -def is_excluded (class_name): - for exp in excludes: - if exp.match (class_name): - for exp in includes: - if exp.match (class_name): - return False - for exp in forces: - if exp.match (class_name): - return False - return True - else: - return False - -docs = [] - -def get_var_type (var): - if var.type_descr != None: - return str (var.type_descr.to_plaintext ("").strip ()) - else: - return None - -for path in args: - if os.path.isdir (path): - paths = [os.path.join (path, file) - for file in os.listdir (path) if file.endswith (".py")] - else: - paths = [path] - for path in paths: - docs.append (epydoc.docparser.parse_docs (path)) - -classes = [] -bases_dict = {} -uses_dict = {} -methods_dict = {} -vars_dict = {} - -for doc in docs: - for var in doc.variables.values (): - if type (var.value) != epydoc.apidoc.ClassDoc: - continue - var_val = var.value - var_name = str (var_val.canonical_name) - var_name = var_name.replace (prefix, "") - classes.append (var_name) - if options.debug: - print var_name - var_vars = var_val.variables.values () - vars_dict[var_name] = [] - methods_dict[var_name] = [] - uses_dict[var_name] = [] - if str (var_val.docstring) != "": - bits = str (var_val.docstring).split ("\n") - for bit in bits: - if bit.strip ().startswith ("@uses:"): - bit = bit.replace ("@uses:", "").strip () - uses_dict[var_name].append (bit) - for var_var in var_vars: - if type (var_var.value) == epydoc.apidoc.GenericValueDoc: - if no_property: - continue - epydoc.docstringparser.parse_docstring (var_var, None) - if options.debug: - print var_name, var_var.name, get_var_type (var_var) - var_type = get_var_type (var_var) - if all_properties or "@doc" in str (var_var.docstring) or var_type: - var_var_name = str (var_var.name.replace (prefix, "")) - vars_dict[var_name].append ((var_var_name, get_var_type (var_var))) - elif type (var_var.value) in (epydoc.apidoc.RoutineDoc, - epydoc.apidoc.StaticMethodDoc): - if no_method: - continue - if (all_methods or "@doc" in str (var_var.value.docstring)) \ - and not "@nodoc" in str (var_var.value.docstring): - methods_dict[var_name].append (str (var_var.name)) - else: - print type (var_var.value) - bases = [str (base.canonical_name).replace (prefix, "") - for base in var_val.bases - if str (base.canonical_name) not in ("object", "")] - if options.debug: - print bases - bases_dict[var_name] = bases - -nodes_dict = {} -var_fields_dict = {} -method_fields_dict = {} -graph = gv.digraph ('g') -gv.setv (graph, 'charset', 'utf-8') -gv.setv (graph, 'overlap', 'false') -gv.setv (graph, 'splines', 'true') -gv.setv (graph, 'rankdir', 'BT') -item = gv.protoedge (graph) -gv.setv (item, 'len', '2') -item = gv.protonode (graph) -gv.setv (item, 'shape', 'plaintext') - -CLASS_COLOR = "#FF6262" -VAR_FIELD_COLOR = "#63BDFF" -METHOD_FIELD_COLOR = "#6EFF62" - -SUPER_EDGE_COLOR = "#AD0006" -VAR_EDGE_COLOR = "#002990" -USE_EDGE_COLOR = "#05C800" - -LABEL_BASE = """< - - - - -%s -
%s
->""" -FIELD_FORMATTER = """ - %s - """ - -def build_record_label (class_name): - fields = "".join ([FIELD_FORMATTER % (VAR_FIELD_COLOR, field, field) - for field in sorted (var_fields_dict[class_name])]) - fields += "".join ([FIELD_FORMATTER % (METHOD_FIELD_COLOR, field, field) - for field in sorted (method_fields_dict[class_name])]) - return LABEL_BASE % (CLASS_COLOR, class_name, class_name, fields) - -def build_simple_label (class_name): - return LABEL_BASE % (CLASS_COLOR, class_name, class_name, "") - -def check_class_node (name): - if name not in nodes_dict: - node = gv.node (graph, name) - gv.setv (node, 'shape', 'plaintext') - gv.setv (node, 'style', 'invis') - if name in var_fields_dict or name in method_fields_dict: - gv.setv (node, 'label', build_record_label (name)) - else: - gv.setv (node, 'label', build_simple_label (name)) - nodes_dict[name] = node - return nodes_dict[name] - -def add_super_edge (class_name, base_name): - check_class_node (class_name) - check_class_node (base_name) - edge = gv.edge (graph, class_name, base_name) - gv.setv (edge, 'arrowhead', 'normal') - gv.setv (edge, 'color', SUPER_EDGE_COLOR) - # FIXME: edge style - -def add_var_edge (class_name, var_name, type_name): - check_class_node (class_name) - check_class_node (type_name) - edge = gv.edge (graph, type_name, class_name) - gv.setv (edge, 'headport', "%s:e" % var_name) - gv.setv (edge, 'arrowhead', 'diamond') - gv.setv (edge, 'color', VAR_EDGE_COLOR) - # FIXME: edge style - -def add_use_edge (class_name, base_name): - check_class_node (class_name) - check_class_node (base_name) - edge = gv.edge (graph, class_name, base_name) - gv.setv (edge, 'arrowhead', 'box') - gv.setv (edge, 'color', USE_EDGE_COLOR) - # FIXME: edge style - -for class_name in classes: - if is_excluded (class_name): - continue - for (var_name, type_name) in vars_dict[class_name]: - if class_name not in var_fields_dict: - var_fields_dict[class_name] = [] - method_fields_dict[class_name] = [] - var_fields_dict[class_name].append (var_name) - for method_name in methods_dict[class_name]: - if class_name not in var_fields_dict: - var_fields_dict[class_name] = [] - method_fields_dict[class_name] = [] - method_fields_dict[class_name].append (method_name) - -for class_name in classes: - if is_excluded (class_name): - continue - for (var_name, type_name) in vars_dict[class_name]: - if not type_name or is_excluded (type_name): - continue - add_var_edge (class_name, var_name, type_name) - for base_name in bases_dict[class_name]: - if is_excluded (base_name): - continue - add_super_edge (class_name, base_name) - for used_name in uses_dict[class_name]: - if is_excluded (used_name): - continue - add_use_edge (class_name, used_name) - -for class_name in classes: - for exp in forces: - if exp.match (class_name): - check_class_node (class_name) - break - -gv.layout (graph, 'dot') -gv.render (graph, 'png', output) diff --git a/umlpy.py b/umlpy.py new file mode 100644 index 0000000..0a3cd48 --- /dev/null +++ b/umlpy.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python +# coding=utf-8 + +''' + umlpy + Author : Guillaume "iXce" Seguin + Email : guillaume@segu.in (or guillaume.seguin@ens.fr) + + # UML-like graph produced for Python # + + Copyright (C) 2009 Guillaume Seguin + + 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +''' + +import epydoc.docparser +import epydoc.docstringparser +import epydoc.apidoc + +import gv + +import sys +import os +import re + +from optparse import OptionParser + +parser = OptionParser() +parser.add_option("-v", dest = "debug", action = "store_true", + default = False, + help = "enables debug output") +parser.add_option("-e", "--exclude", dest = "excludes", action = "append", + default = [], + help = "classes matching this regexp will be excluded \ + from display") +parser.add_option("-i", "--include", dest = "includes", action = "append", + default = [], + help = "classes matching this regexp will be included \ + in display even if they were excluded by exclude \ + regexps") +parser.add_option("-p", "--prefix", dest = "prefix", action = "store", + default = "", + help = "prefix which will be stripped of class names") +parser.add_option("-f", "--force", dest = "forces", action = "append", + default = [], + help = "classes matching this regexp will be forced into \ + display") +parser.add_option("--all-methods", dest = "all_methods", + action = "store_true", default = False, + help = "shows all methods") +parser.add_option("--all-properties", dest = "all_properties", + action = "store_true", default = False, + help = "shows all properties") +parser.add_option("--no-method", dest = "no_method", + action = "store_true", default = False, + help = "shows no method") +parser.add_option("--no-property", dest = "no_property", + action = "store_true", default = False, + help = "shows no property") +parser.add_option("-o", "--output", dest = "output", action = "store", + default = "uml.png", + help = "output file") + +(options, args) = parser.parse_args () + +excludes = reduce (lambda x, y: x + y, + map (lambda s: s.split(","), options.excludes), []) +includes = reduce (lambda x, y: x + y, + map (lambda s: s.split(","), options.includes), []) +forces = reduce (lambda x, y: x + y, + map (lambda s: s.split(","), options.forces), []) +prefix = options.prefix +all_methods = options.all_methods +all_properties = options.all_properties +no_method = options.no_method +no_property = options.no_property +output = options.output + +print "Settings" +print "--------" +print "Output file :", output +print "Prefix :", prefix +print "Show all methods :", all_methods +print "Show all properties :", all_properties +print "Show no method :", no_method +print "Show no propertie :", no_property +print "Excludes :", excludes +print "Includes :", includes +print "Forces :", forces + +excludes = [re.compile (exp) + for exp in excludes] +includes = [re.compile (exp) + for exp in includes] +forces = [re.compile (exp) + for exp in forces] + +def is_excluded (class_name): + for exp in excludes: + if exp.match (class_name): + for exp in includes: + if exp.match (class_name): + return False + for exp in forces: + if exp.match (class_name): + return False + return True + else: + return False + +docs = [] + +def get_var_type (var): + if var.type_descr != None: + return str (var.type_descr.to_plaintext ("").strip ()) + else: + return None + +for path in args: + if os.path.isdir (path): + paths = [os.path.join (path, file) + for file in os.listdir (path) if file.endswith (".py")] + else: + paths = [path] + for path in paths: + docs.append (epydoc.docparser.parse_docs (path)) + +classes = [] +bases_dict = {} +uses_dict = {} +methods_dict = {} +vars_dict = {} + +for doc in docs: + for var in doc.variables.values (): + if type (var.value) != epydoc.apidoc.ClassDoc: + continue + var_val = var.value + var_name = str (var_val.canonical_name) + var_name = var_name.replace (prefix, "") + classes.append (var_name) + if options.debug: + print var_name + var_vars = var_val.variables.values () + vars_dict[var_name] = [] + methods_dict[var_name] = [] + uses_dict[var_name] = [] + if str (var_val.docstring) != "": + bits = str (var_val.docstring).split ("\n") + for bit in bits: + if bit.strip ().startswith ("@uses:"): + bit = bit.replace ("@uses:", "").strip () + uses_dict[var_name].append (bit) + for var_var in var_vars: + if type (var_var.value) == epydoc.apidoc.GenericValueDoc: + if no_property: + continue + epydoc.docstringparser.parse_docstring (var_var, None) + if options.debug: + print var_name, var_var.name, get_var_type (var_var) + var_type = get_var_type (var_var) + if all_properties or "@doc" in str (var_var.docstring) or var_type: + var_var_name = str (var_var.name.replace (prefix, "")) + vars_dict[var_name].append ((var_var_name, get_var_type (var_var))) + elif type (var_var.value) in (epydoc.apidoc.RoutineDoc, + epydoc.apidoc.StaticMethodDoc): + if no_method: + continue + if (all_methods or "@doc" in str (var_var.value.docstring)) \ + and not "@nodoc" in str (var_var.value.docstring): + methods_dict[var_name].append (str (var_var.name)) + else: + print type (var_var.value) + bases = [str (base.canonical_name).replace (prefix, "") + for base in var_val.bases + if str (base.canonical_name) not in ("object", "")] + if options.debug: + print bases + bases_dict[var_name] = bases + +nodes_dict = {} +var_fields_dict = {} +method_fields_dict = {} +graph = gv.digraph ('g') +gv.setv (graph, 'charset', 'utf-8') +gv.setv (graph, 'overlap', 'false') +gv.setv (graph, 'splines', 'true') +gv.setv (graph, 'rankdir', 'BT') +item = gv.protoedge (graph) +gv.setv (item, 'len', '2') +item = gv.protonode (graph) +gv.setv (item, 'shape', 'plaintext') + +CLASS_COLOR = "#FF6262" +VAR_FIELD_COLOR = "#63BDFF" +METHOD_FIELD_COLOR = "#6EFF62" + +SUPER_EDGE_COLOR = "#AD0006" +VAR_EDGE_COLOR = "#002990" +USE_EDGE_COLOR = "#05C800" + +LABEL_BASE = """< + + + + +%s +
%s
+>""" +FIELD_FORMATTER = """ + %s + """ + +def build_record_label (class_name): + fields = "".join ([FIELD_FORMATTER % (VAR_FIELD_COLOR, field, field) + for field in sorted (var_fields_dict[class_name])]) + fields += "".join ([FIELD_FORMATTER % (METHOD_FIELD_COLOR, field, field) + for field in sorted (method_fields_dict[class_name])]) + return LABEL_BASE % (CLASS_COLOR, class_name, class_name, fields) + +def build_simple_label (class_name): + return LABEL_BASE % (CLASS_COLOR, class_name, class_name, "") + +def check_class_node (name): + if name not in nodes_dict: + node = gv.node (graph, name) + gv.setv (node, 'shape', 'plaintext') + gv.setv (node, 'style', 'invis') + if name in var_fields_dict or name in method_fields_dict: + gv.setv (node, 'label', build_record_label (name)) + else: + gv.setv (node, 'label', build_simple_label (name)) + nodes_dict[name] = node + return nodes_dict[name] + +def add_super_edge (class_name, base_name): + check_class_node (class_name) + check_class_node (base_name) + edge = gv.edge (graph, class_name, base_name) + gv.setv (edge, 'arrowhead', 'normal') + gv.setv (edge, 'color', SUPER_EDGE_COLOR) + # FIXME: edge style + +def add_var_edge (class_name, var_name, type_name): + check_class_node (class_name) + check_class_node (type_name) + edge = gv.edge (graph, type_name, class_name) + gv.setv (edge, 'headport', "%s:e" % var_name) + gv.setv (edge, 'arrowhead', 'diamond') + gv.setv (edge, 'color', VAR_EDGE_COLOR) + # FIXME: edge style + +def add_use_edge (class_name, base_name): + check_class_node (class_name) + check_class_node (base_name) + edge = gv.edge (graph, class_name, base_name) + gv.setv (edge, 'arrowhead', 'box') + gv.setv (edge, 'color', USE_EDGE_COLOR) + # FIXME: edge style + +for class_name in classes: + if is_excluded (class_name): + continue + for (var_name, type_name) in vars_dict[class_name]: + if class_name not in var_fields_dict: + var_fields_dict[class_name] = [] + method_fields_dict[class_name] = [] + var_fields_dict[class_name].append (var_name) + for method_name in methods_dict[class_name]: + if class_name not in var_fields_dict: + var_fields_dict[class_name] = [] + method_fields_dict[class_name] = [] + method_fields_dict[class_name].append (method_name) + +for class_name in classes: + if is_excluded (class_name): + continue + for (var_name, type_name) in vars_dict[class_name]: + if not type_name or is_excluded (type_name): + continue + add_var_edge (class_name, var_name, type_name) + for base_name in bases_dict[class_name]: + if is_excluded (base_name): + continue + add_super_edge (class_name, base_name) + for used_name in uses_dict[class_name]: + if is_excluded (used_name): + continue + add_use_edge (class_name, used_name) + +for class_name in classes: + for exp in forces: + if exp.match (class_name): + check_class_node (class_name) + break + +gv.layout (graph, 'dot') +gv.render (graph, 'png', output) -- cgit v1.1