3 # Copyright 2008 the Melange authors.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """A script which produces a UML diagram from the data model found in the
20 The output can be found in a file called model-map.png in the same directory as
25 '"Tim \'mithro\' Ansell" <mithro@mithis.com>',
31 from types
import TypeType
37 sys
.path
.append(os
.path
.join("..", "thirdparty", "google_appengine"))
39 sys
.path
.append(os
.path
.join("..", "app"))
42 import google
.appengine
.ext
.db
44 G
= pygraphviz
.AGraph()
45 G
.graph_attr
['label'] = '-'
47 import soc
.models
as models
48 for file in os
.listdir(os
.path
.dirname(models
.__file
__)):
49 if not file.endswith(".py"):
51 if "__init__" in file:
54 modelname
= os
.path
.basename(file)[:-3]
56 #model = __import__("app.soc.models.%s" % modelname, fromlist=[modelname])
57 exec("import soc.models.%s as model" % modelname
)
59 # Add the module to the graph
60 for klassname
in dir(model
):
61 klass
= getattr(model
, klassname
)
62 if not isinstance(klass
, TypeType
):
65 # Create arrows to the parent classes
66 for parent
in klass
.__bases
__:
67 G
.add_edge(klassname
, parent
.__name
__)
68 edge
= G
.get_edge(klassname
, parent
.__name
__)
69 edge
.attr
['arrowhead'] = "empty"
73 for attrname
in dir(klass
):
74 attr
= getattr(klass
, attrname
)
76 # Is it an appengine datastore type?
77 if type(attr
) in google
.appengine
.ext
.db
.__dict
__.values():
78 # References get arrows to the other class
79 if isinstance(attr
, google
.appengine
.ext
.db
.ReferenceProperty
):
80 hasa
= attr
.reference_class
.__name
__
81 G
.add_edge(hasa
, klassname
)
82 edge
= G
.get_edge(hasa
, klassname
)
83 edge
.attr
['arrowhead'] = 'inv'
85 refs
+= "+ %s: %s\l" % (attrname
, type(attr
).__name
__[:-8])
87 # Ignore back references
88 elif isinstance(attr
, google
.appengine
.ext
.db
._ReverseReferenceProperty
):
91 # Check that the property is not inherited for a parent class
93 for parent
in klass
.__bases
__:
94 if hasattr(parent
, attrname
):
98 attrs
+= "+ %s: %s\l" % (attrname
, type(attr
).__name
__[:-8])
99 label
= "{%s|%s|%s}" % (klassname
, attrs
, refs
)
101 G
.add_node(klassname
)
102 node
= G
.get_node(klassname
)
103 node
.attr
['label'] = label
104 node
.attr
['shape'] = "record"
108 print "Was unable to import %s: %s" % (modelname
, e
)
109 traceback
.print_exc()
112 G
.draw('model-map.png')
114 if __name__
== "__main__":