From 7a4f561e851fdc7246d804c3abb6748b8a4199a6 Mon Sep 17 00:00:00 2001 From: gnowgi Date: Thu, 15 Mar 2012 16:19:20 +0530 Subject: master trunk of gnowsys-studio --- demo/graphviz/__init__.py | 0 demo/graphviz/admin.py | 89 +++++++++++++ demo/graphviz/interfaces.py | 38 ++++++ demo/graphviz/management/__init__.py | 0 demo/graphviz/management/commands/__init__.py | 0 demo/graphviz/management/commands/modelviz.py | 173 ++++++++++++++++++++++++++ demo/graphviz/models.py | 119 ++++++++++++++++++ demo/graphviz/templates/graphviz/dot_file.dot | 6 + demo/graphviz/urls.py | 26 ++++ demo/graphviz/views.py | 61 +++++++++ 10 files changed, 512 insertions(+) create mode 100644 demo/graphviz/__init__.py create mode 100644 demo/graphviz/admin.py create mode 100644 demo/graphviz/interfaces.py create mode 100644 demo/graphviz/management/__init__.py create mode 100644 demo/graphviz/management/commands/__init__.py create mode 100644 demo/graphviz/management/commands/modelviz.py create mode 100644 demo/graphviz/models.py create mode 100644 demo/graphviz/templates/graphviz/dot_file.dot create mode 100644 demo/graphviz/urls.py create mode 100644 demo/graphviz/views.py (limited to 'demo/graphviz') diff --git a/demo/graphviz/__init__.py b/demo/graphviz/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/demo/graphviz/admin.py b/demo/graphviz/admin.py new file mode 100644 index 0000000..fb81042 --- /dev/null +++ b/demo/graphviz/admin.py @@ -0,0 +1,89 @@ +# Copyright (c) 2011, 2012 Free Software Foundation + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +# This project incorporates work covered by the following copyright and permission notice: + +# Copyright (c) 2009, Julien Fache +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: + +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of the author nor the names of other +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. + +# Copyright (c) 2011, 2012 Free Software Foundation + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from django.contrib import admin +from models import * + +class GraphAdmin(admin.ModelAdmin): + list_display = ('slug', 'name', 'content_type', 'view_dot_file', 'download_dot_file', 'download_image') + list_filter = ('content_type',) +admin.site.register(Graph, GraphAdmin) + + +class NodeVisualAdmin(admin.ModelAdmin): + list_display = ('shape', 'graph', 'content_type') + list_filter = ('content_type', 'graph') +admin.site.register(NodeVisual, NodeVisualAdmin) + + +class ArrowVisualAdmin(admin.ModelAdmin): + list_display = ('shape', 'modifier', 'graph', 'content_type') + list_filter = ('content_type', 'graph') +admin.site.register(ArrowVisual, ArrowVisualAdmin) + + +class CacheImageAdmin(admin.ModelAdmin): + list_display = ('graph', 'graphic', 'valid', 'file', 'date') + list_filter = ('valid', 'graph') +admin.site.register(CacheImage, CacheImageAdmin) diff --git a/demo/graphviz/interfaces.py b/demo/graphviz/interfaces.py new file mode 100644 index 0000000..f1c76c9 --- /dev/null +++ b/demo/graphviz/interfaces.py @@ -0,0 +1,38 @@ + +# Copyright (c) 2011, 2012 Free Software Foundation + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +""" +""" + + +class IGraphRoot: + def gv_edges(self, graph): + raise Exception('not implemented') + def gv_nodes(self, graph): + raise Exception('not implemented') + +class INode: + def gv_node_label(self, graph): + return unicode(self) + +class IEdge: + def gv_ends(self, graph): + ''' should returns (node_source, node_target) + ''' + raise Exception('not implemented') + def gv_edge_label(self, graph): + return unicode(self) diff --git a/demo/graphviz/management/__init__.py b/demo/graphviz/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/demo/graphviz/management/commands/__init__.py b/demo/graphviz/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/demo/graphviz/management/commands/modelviz.py b/demo/graphviz/management/commands/modelviz.py new file mode 100644 index 0000000..30d8421 --- /dev/null +++ b/demo/graphviz/management/commands/modelviz.py @@ -0,0 +1,173 @@ + +# Copyright (c) 2011, 2012 Free Software Foundation + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +#!/usr/bin/env python +import getopt, sys + +from optparse import make_option + +from django.template import Template, Context +from django.db import models +from django.db.models import get_models +from django.db.models.fields.related import \ + ForeignKey, OneToOneField, ManyToManyField + +from django.core.management.base import AppCommand + +try: + from django.db.models.fields.generic import GenericRelation +except ImportError: + from django.contrib.contenttypes.generic import GenericRelation + +head_template = """ +digraph name { + fontname = "Helvetica" + fontsize = 8 + + node [ + fontname = "Helvetica" + fontsize = 8 + shape = "plaintext" + ] + edge [ + fontname = "Helvetica" + fontsize = 8 + ] + +""" + +body_template = """ + {% for model in models %} + {% for relation in model.relations %} + {{ relation.target }} [label=< + + +
{{ relation.target }}
+ >] + {{ model.name }} -> {{ relation.target }} + [label="{{ relation.name }}"] {{ relation.arrows }}; + {% endfor %} + {% endfor %} + + {% for model in models %} + {{ model.name }} [label=< + + + + {% if not disable_fields %} + {% for field in model.fields %} + + + {% endfor %} + {% endif %} +
{{ model.name }}
{{ field.name }}{{ field.type }}
+ >] + {% endfor %} +""" + +tail_template = """ +} +""" + +def generate_dot(app_labels, **kwargs): + disable_fields = kwargs.get('disable_fields', False) + + dot = head_template + + for app_label in app_labels: + app = models.get_app(app_label) + graph = Context({ + 'name': '"%s"' % app.__name__, + 'disable_fields': disable_fields, + 'models': [] + }) + + for appmodel in get_models(app): + model = { + 'name': appmodel.__name__, + 'fields': [], + 'relations': [] + } + + # model attributes + def add_attributes(): + model['fields'].append({ + 'name': field.name, + 'type': type(field).__name__, + 'blank': field.blank + }) + + for field in appmodel._meta.fields: + add_attributes() + + if appmodel._meta.many_to_many: + for field in appmodel._meta.many_to_many: + add_attributes() + + # relations + def add_relation(extras=""): + _rel = { + 'target': field.rel.to.__name__, + 'type': type(field).__name__, + 'name': field.name, + 'arrows': extras + } + if _rel not in model['relations']: + model['relations'].append(_rel) + + for field in appmodel._meta.fields: + if isinstance(field, ForeignKey): + add_relation() + elif isinstance(field, OneToOneField): + add_relation("[arrowhead=none arrowtail=none]") + + if appmodel._meta.many_to_many: + for field in appmodel._meta.many_to_many: + if isinstance(field, ManyToManyField): + add_relation("[arrowhead=normal arrowtail=normal]") + elif isinstance(field, GenericRelation): + add_relation( + '[style="dotted"] [arrowhead=normal arrowtail=normal]') + graph['models'].append(model) + + t = Template(body_template) + dot += '\n' + t.render(graph) + + dot += '\n' + tail_template + + return dot + +class Command(AppCommand): + option_list = AppCommand.option_list + ( + make_option('--disable_fields', default=False, dest='disable_fields', + help='Hide fields.'), + ) + help = "Prints a Graphviz .dot file from models ." + + def handle(self, *app_labels, **options): + disable_fields = options.get('disable_fields', False) + return generate_dot(app_labels, **options) + + diff --git a/demo/graphviz/models.py b/demo/graphviz/models.py new file mode 100644 index 0000000..68d86b2 --- /dev/null +++ b/demo/graphviz/models.py @@ -0,0 +1,119 @@ + +# Copyright (c) 2011, 2012 Free Software Foundation + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from django.db import models +from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes import generic + +class Graph(models.Model): + """ the object defined by the generic relation should have + a method gv_links(graph) that returns a sequence of links. + a method gv_nodes(graph) that returns a sequence of nodes. + + a link should have a method gv_ends(graph) that returns a sequence + of nodes [start, end]. + + a link may have a method gv_visual(graph) that returns a ArrowVisual instance or None + + a node may have a method gv_visual(graph) that returns + a NodeVisual instance or None. + + links may have a gv_link_label(graph) method + nodes may have a gv_node_label(graph) method + + see also interfaces.py module. + """ + slug = models.SlugField(primary_key=True) + name = models.CharField(max_length=50) + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey('content_type', 'object_id') + + def view_dot_file(self): + return 'view' % self.slug + view_dot_file.allow_tags = True + + def download_dot_file(self): + return 'download' % self.slug + download_dot_file.allow_tags = True + + def download_image(self): + return 'download (TODO)' % self.slug + download_image.allow_tags = True + + def __unicode__(self): + return self.name + class Meta: + verbose_name_plural = 'Graphes' + +NODE_SHAPE_CHOICES = (('box','Box'), + ('circle','Circle'), + ('doublecircle','Double circle'), + ('box3d','Box 3D'), + ('diamond','Diamond'), + ) +class NodeVisual(models.Model): + """ the content_type attribute is used to define the default Node + when no method gv_node is provided. + """ + shape = models.CharField(max_length=50, default='circle', choices=NODE_SHAPE_CHOICES) + graph = models.ForeignKey(Graph) + content_type = models.ForeignKey(ContentType) + + def __unicode__(self): + return self.shape + +ARROW_SHAPE_CHOICES = (('box','box'), + ('crow','crow'), + ('diamond','diamond'), + ('dot','dot'), + ('inv','inv'), + ('none','none'), + ('normal','normal'), + ('tee','tee'), + ('vee','vee'), + ) +ARROW_MODIFIER_CHOICES = (('l','left'), + ('r','right'), + ('o','non-filled'), + ) +class ArrowVisual(models.Model): + """ the content_type attribute is used to define the default Arrow + when no method gv_arrow is provided. + """ + shape = models.CharField(max_length=50, default='normal', choices=ARROW_SHAPE_CHOICES) + modifier = models.CharField(max_length=1, default='r', choices=ARROW_MODIFIER_CHOICES) + graph = models.ForeignKey(Graph) + content_type = models.ForeignKey(ContentType) + + def __unicode__(self): + return self.shape + +class CacheImage(models.Model): + date = models.DateTimeField(auto_now_add=True) + valid = models.BooleanField(default=True) + graph = models.ForeignKey(Graph) + file = models.ImageField(upload_to='graph_images') + + def graphic(self): + return '' % (self.pk, self.file.url) + graphic.allow_tags = True + + def __unicode__(self): + return self.graph.name + class Meta: + verbose_name_plural = 'Caches images' diff --git a/demo/graphviz/templates/graphviz/dot_file.dot b/demo/graphviz/templates/graphviz/dot_file.dot new file mode 100644 index 0000000..1b097ea --- /dev/null +++ b/demo/graphviz/templates/graphviz/dot_file.dot @@ -0,0 +1,6 @@ + +digraph G { + {% for edge in graph.edges %} + "{{ edge.start_node_label }}" -> "{{ edge.end_node_label }}" [label = "{{ edge.label }}"]; + {% endfor %} +} \ No newline at end of file diff --git a/demo/graphviz/urls.py b/demo/graphviz/urls.py new file mode 100644 index 0000000..5cf40c7 --- /dev/null +++ b/demo/graphviz/urls.py @@ -0,0 +1,26 @@ + +# Copyright (c) 2011, 2012 Free Software Foundation + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from django.conf.urls.defaults import * + +import views + +urlpatterns = patterns('', + (r'^dot_file/(?P.*)/$', views.dot_file, {'template':'graphviz/dot_file.dot'}), + (r'^dot_view/(?P.*)/$', views.dot_file, {'view':True, 'template':'graphviz/dot_file.dot'}), + (r'^image_file/(?P.*)/$', views.image_file), +) diff --git a/demo/graphviz/views.py b/demo/graphviz/views.py new file mode 100644 index 0000000..aca8730 --- /dev/null +++ b/demo/graphviz/views.py @@ -0,0 +1,61 @@ + +# Copyright (c) 2011, 2012 Free Software Foundation + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from django.http import HttpResponse +from django.shortcuts import render_to_response +from django.template import RequestContext +from models import Graph + +from django.template import Template + +from os import system +from django.conf import settings + +import os +from os.path import join +_tmpdir = '/tmp' #os.environ['TMP'] + +class TEdge: + def __init__(self, data, graph): + self.start_node, self.end_node = data.gv_ends(graph) + self.start_node_label = self.start_node.gv_node_label(graph) + self.end_node_label = self.end_node.gv_node_label(graph) + self.label = data.gv_edge_label(graph) +class TGraph: + def __init__(self, graph): + self.edges = [] + for e in graph.content_object.gv_edges(graph): + self.edges.append(TEdge(e, graph)) + +def dot_file(request, slug, view=False, template='graphviz/dot_file.dot'): + graph = Graph.objects.get(slug=slug) + context = {'graph':TGraph(graph)} + response = render_to_response(template, context, mimetype='text/plain', + context_instance=RequestContext(request)) + if not view: + response['Content-Disposition'] = 'attachment; filename=%s.dot' % slug + return response + +def image_file(request, slug, template='graphviz/dot_file.html'): + resp = dot_file(request, slug, template) + path_dot = join(_tmpdir, 'graphviz_tmp.dot') + tdot = open(path_dot, 'w') + tdot.write(resp.content) + tdot.close() + system('%s %s Tpng -o %s.png' % (settings.GRAPHVIZ_DOT_CMD, path_dot, path_dot)) + + return HttpResponse('image '+path_dot+'.png') -- cgit v1.1