scripts/graph.py
author Lennard de Rijk <ljvderijk@gmail.com>
Fri, 24 Jul 2009 20:49:59 +0200
changeset 2675 49cf6a8af70a
parent 417 a88affc13f98
permissions -rwxr-xr-x
Added template for a notification upon arrival of a new Request.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
243
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     1
#!/usr/bin/python2.5
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     2
#
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     3
# Copyright 2008 the Melange authors.
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     4
#
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     5
# Licensed under the Apache License, Version 2.0 (the "License");
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     6
# you may not use this file except in compliance with the License.
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     7
# You may obtain a copy of the License at
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     8
#
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
     9
#   http://www.apache.org/licenses/LICENSE-2.0
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    10
#
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    11
# Unless required by applicable law or agreed to in writing, software
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    12
# distributed under the License is distributed on an "AS IS" BASIS,
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    14
# See the License for the specific language governing permissions and
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    15
# limitations under the License.
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    16
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    17
"""A script which produces a UML diagram from the data model found in the
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    18
models directory.
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    19
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    20
The output can be found in a file called model-map.png in the same directory as
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    21
this file.
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    22
"""
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    23
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    24
__authors__ = [
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    25
  '"Tim \'mithro\' Ansell" <mithro@mithis.com>',
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    26
]
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    27
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    28
import os
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    29
import os.path
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    30
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    31
from types import TypeType
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    32
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    33
import pygraphviz
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    34
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    35
import sys
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    36
# App Engine
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    37
sys.path.append(os.path.join("..", "thirdparty", "google_appengine"))
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    38
# Our app
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    39
sys.path.append(os.path.join("..", "app"))
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    40
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    41
def main(argv):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    42
  import google.appengine.ext.db
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    43
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    44
  G = pygraphviz.AGraph()
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    45
  G.graph_attr['label'] = '-'
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    46
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    47
  import soc.models as models
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    48
  for file in os.listdir(os.path.dirname(models.__file__)):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    49
    if not file.endswith(".py"):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    50
      continue
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    51
    if "__init__" in file:
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    52
      continue
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    53
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    54
    modelname = os.path.basename(file)[:-3]
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    55
    try:
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    56
      #model = __import__("app.soc.models.%s" % modelname, fromlist=[modelname])
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    57
      exec("import soc.models.%s as model" % modelname)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    58
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    59
      # Add the module to the graph
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    60
      for klassname in dir(model):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    61
        klass = getattr(model, klassname)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    62
        if not isinstance(klass, TypeType):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    63
          continue
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    64
417
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    65
        # Create arrows to the parent classes
243
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    66
        for parent in klass.__bases__:
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    67
          G.add_edge(klassname, parent.__name__)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    68
          edge = G.get_edge(klassname, parent.__name__)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    69
          edge.attr['arrowhead'] = "empty"
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    70
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    71
        refs = ""
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    72
        attrs = ""
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    73
        for attrname in dir(klass):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    74
          attr = getattr(klass, attrname)
417
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    75
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    76
          # Is it an appengine datastore type?
243
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    77
          if type(attr) in google.appengine.ext.db.__dict__.values():
417
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    78
            # References get arrows to the other class
243
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    79
            if isinstance(attr, google.appengine.ext.db.ReferenceProperty):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    80
              hasa = attr.reference_class.__name__
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    81
              G.add_edge(hasa, klassname)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    82
              edge = G.get_edge(hasa, klassname)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    83
              edge.attr['arrowhead'] = 'inv'
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    84
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    85
              refs += "+ %s: %s\l" % (attrname, type(attr).__name__[:-8])
417
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    86
            
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    87
            # Ignore back references
243
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    88
            elif isinstance(attr, google.appengine.ext.db._ReverseReferenceProperty):
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    89
              pass
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    90
            else:
417
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    91
              # Check that the property is not inherited for a parent class
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    92
              local = True
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    93
              for parent in klass.__bases__:
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    94
                if hasattr(parent, attrname):
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    95
                  local = False
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    96
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    97
              if local:
a88affc13f98 Do not include attributes which are inherited.
Tim Ansell <mithro@gmail.com>
parents: 243
diff changeset
    98
                attrs += "+ %s: %s\l" % (attrname, type(attr).__name__[:-8])
243
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
    99
        label = "{%s|%s|%s}" % (klassname, attrs, refs)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   100
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   101
        G.add_node(klassname)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   102
        node = G.get_node(klassname)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   103
        node.attr['label'] = label
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   104
        node.attr['shape'] = "record"
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   105
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   106
    except Exception, e:
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   107
      import traceback
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   108
      print "Was unable to import %s: %s" % (modelname, e)
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   109
      traceback.print_exc()
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   110
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   111
  G.layout(prog='dot')
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   112
  G.draw('model-map.png')
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   113
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   114
if __name__ == "__main__":
b0eeea9d6da6 Tool to graph the data model.
Tim Ansell <mithro@gmail.com>
parents:
diff changeset
   115
  main(sys.argv)