adding database schema to documentation.
--- a/createdoc.py Sun Dec 18 11:49:12 2011 +0100
+++ b/createdoc.py Sun Dec 18 11:49:46 2011 +0100
@@ -10,6 +10,7 @@
from iro.user import User as Current
from iro.newuser import User as New
+from createerm import createSchemaPlot,tables
@@ -99,11 +100,20 @@
self.args=[Arg(a,m) for a in args]
_, self.rets=ret(m)
+class Table(Link):
+ def __init__(self,cls):
+ name=cls.__name__
+ self.tablename=cls.__tablename__
+ title=self.tablename[0].upper()+self.tablename[1:]
+ Link.__init__(self,name,title)
+ self.description = cls.__doc__.split("\n")[0].decode("utf8")
+
def main():
sites=[Site("index.html","Iro"),
Site("current.html","API Documentation"),
Site("new.html","geplante API Documentation"),
+ Site("database.html","Datenbank Schema"),
Site("impressum.html","Impressum"),
]
@@ -132,7 +142,9 @@
Method("routes",new_methods),
Method("defaultRoute",new_methods),
]
-
+
+ t = [Table(f.class_) for f in tables]
+ createSchemaPlot('doc/images/db-schema.svg')
for site in sites:
print("generiere %s" % site.name)
@@ -140,7 +152,7 @@
def a(s):
if s == site:
return {"class":"menu active"}
- stream = tmpl.generate(sites=sites,active=a,current=current,new=newm)
+ stream = tmpl.generate(sites=sites,active=a,current=current,new=newm,tables=t)
with open('doc/'+site.name, "w") as g:
g.write(stream.render('html', doctype='html'))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/createerm.py Sun Dec 18 11:49:46 2011 +0100
@@ -0,0 +1,48 @@
+from iro import schema
+
+from sqlalchemy.orm import class_mapper
+tables = []
+for attr in schema.__tables__:
+ if attr[0] == '_': continue
+ try:
+ cls = getattr(schema, attr)
+ tables.append(class_mapper(cls))
+ except:
+ pass
+
+
+#schema plot
+def createSchemaPlot(fname):
+ from sqlalchemy_schemadisplay3 import create_schema_graph
+ graph = create_schema_graph(metadata=schema.Base.metadata,
+ show_datatypes=True, # The image too large if datatypes shown
+ show_indexes=True, # ditto for indexes
+ rankdir='LR', # From left to right (instead of top to bottom)
+ concentrate=True, # Don't try to join the relation lines together
+ )
+
+ graph.set_size('6.5,10')
+ #graph.set_ratio("fill")
+ graph.write_svg(fname)
+
+#umlplot
+def createUMLPlot(fname):
+ from sqlalchemy_schemadisplay3 import create_uml_graph
+ from sqlalchemy.orm import class_mapper
+ mappers = []
+ for attr in dir(schema.model):
+ if attr[0] == '_': continue
+ try:
+ cls = getattr(schema.model, attr)
+ mappers.append(class_mapper(cls))
+ except:
+ pass
+ #pass them to the function and set some formatting options
+ graph = create_uml_graph(mappers,
+ show_operations=False, # not necessary in this case
+ show_multiplicity_one=True, # some people like to see the ones
+ show_attributes=True,
+ )
+ graph.set_size('6,5')
+ graph.set_ratio("fill")
+ graph.write_png('test.png')
--- a/doc/current.html Sun Dec 18 11:49:12 2011 +0100
+++ b/doc/current.html Sun Dec 18 11:49:46 2011 +0100
@@ -19,7 +19,7 @@
<div id="head">
<h1 id="logo"><a href="index.html" class="logo" title="Netzguerilla"><span>Netzguerilla</span></a></h1>
<ul id="menu">
- <li><a href="index.html" class="menu">Iro</a></li><li><a href="current.html" class="menu active">API Documentation</a></li><li><a href="new.html" class="menu">geplante API Documentation</a></li><li><a href="impressum.html" class="menu">Impressum</a></li>
+ <li><a href="index.html" class="menu">Iro</a></li><li><a href="current.html" class="menu active">API Documentation</a></li><li><a href="new.html" class="menu">geplante API Documentation</a></li><li><a href="database.html" class="menu">Datenbank Schema</a></li><li><a href="impressum.html" class="menu">Impressum</a></li>
</ul>
</div>
</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/database.html Sun Dec 18 11:49:46 2011 +0100
@@ -0,0 +1,75 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+
+ <head>
+ <title>Iro · Datenbank</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <meta charset="utf-8">
+ <meta name="description" content="">
+ <meta name="keywords" content="">
+ <link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
+ <link rel="stylesheet" href="css/reset.css" type="text/css" media="screen">
+ <link rel="stylesheet" href="css/960.css" type="text/css" media="screen">
+ <link rel="stylesheet" href="css/style.css" type="text/css" media="screen">
+ <!--[if IE]><link rel="stylesheet" href="css/style-ie.css" type="text/css" media="screen" /><![endif] -->
+ </head>
+ <body>
+ <div id="head-container">
+ <div id="head">
+ <h1 id="logo"><a href="index.html" class="logo" title="Netzguerilla"><span>Netzguerilla</span></a></h1>
+ <ul id="menu">
+ <li><a href="index.html" class="menu">Iro</a></li><li><a href="current.html" class="menu">API Documentation</a></li><li><a href="new.html" class="menu">geplante API Documentation</a></li><li><a href="database.html" class="menu active">Datenbank Schema</a></li><li><a href="impressum.html" class="menu">Impressum</a></li>
+ </ul>
+ </div>
+ </div>
+ <div id="content-container">
+ <div id="content" class="container_12">
+ <div id="main" class="grid_9">
+ <h2>Datenbank Schema</h2>
+ <div class="item">
+ <p>
+ </p>
+ <ol>
+ <li value="1">1. <a href="#schema">Datenbankschema</a></li>
+ <li value="3">3.
+ <a href="#tables">Tabellen</a>
+ <ol>
+ <li value="2.1">2.1 <a href="#table-apiuser">Apiuser</a></li><li value="2.2">2.2 <a href="#table-job">Job</a></li><li value="2.3">2.3 <a href="#table-message">Message</a></li><li value="2.4">2.4 <a href="#table-offer">Offer</a></li><li value="2.5">2.5 <a href="#table-userright">Userright</a></li>
+ </ol>
+ </li>
+ </ol>
+ </div><div class="item" id="schema">
+ <h3>Schema</h3>
+ <img src="images/db-schema.svg">
+ <p>Dies ist eine Übersicht der benutzen Tabellen die Iro benötigt.</p>
+ </div><div class="item" id="tables">
+ <h3>Tabellen</h3>
+ <div class="item" id="table-apiuser">
+ <h4>Apiuser</h4>
+ <p>Die Benutzerdatenbank von Iro.</p>
+ </div><div class="item" id="table-job">
+ <h4>Job</h4>
+ <p>Ein kompletter Auftrag, der an Iro zum verschicken übergeben wird. Status zeigt den generellen Status des Auftrages an (<em>init</em>, <em>started</em>, <em>sending</em>, <em>sended</em> oder <em>error</em>). <em>info</em> wird verwendet um dem Benutzer eine Möglickeit zu geben verschiede Auftragsgruppen zu erstellen.</p>
+ </div><div class="item" id="table-message">
+ <h4>Message</h4>
+ <p>Wenn ein Vorgang von Iro Kosten erzeugt hat wird eine neue Zeile eingefügt. Solange nicht bezahlt wurde ist <em>isBilled=0</em>.</p>
+ </div><div class="item" id="table-offer">
+ <h4>Offer</h4>
+ <p>Alle Routen über die SMS, Faxe und Mails verschickt werden könnnen. <em>provider</em>, <em>typ</em> und <em>route</em> werden verwendet, um die entsprechenden Zugangsdaten laden zu können.</p>
+ </div><div class="item" id="table-userright">
+ <h4>Userright</h4>
+ <p>Über welche Routen darf ein Benutzer Daten verschicken und welches sind die Standardrouten (<em>isDefault=1</em>) für den Benuter.</p>
+ </div>
+ </div>
+ </div>
+ <div class="clear"></div>
+ </div>
+ </div>
+ <div id="foot-container">
+ <div id="foot">
+ <p>© 2010-2011 <a href="impressum.html">Netzguerilla.net</a>.</p>
+ </div>
+ </div>
+ </body>
+</html>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/images/db-schema.svg Sun Dec 18 11:49:46 2011 +0100
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.26.3 (20100126.1600)
+ -->
+<!-- Title: G Pages: 1 -->
+<svg width="468pt" height="131pt"
+ viewBox="0.00 0.00 468.00 131.29" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph1" class="graph" transform="scale(0.89313 0.89313) rotate(0) translate(4 143)">
+<title>G</title>
+<polygon fill="white" stroke="white" points="-4,5 -4,-143 521,-143 521,5 -4,5"/>
+<!-- message -->
+<g id="node1" class="node"><title>message</title>
+<polygon fill="none" stroke="black" points="8,-25.5 8,-118.5 98,-118.5 98,-25.5 8,-25.5"/>
+<text text-anchor="start" x="36.5" y="-109.367" font-family="Bitstream-Vera Sans" font-size="7.00">message</text>
+<polygon fill="none" stroke="black" points="9,-103 9,-105 97,-105 97,-103 9,-103"/>
+<text text-anchor="start" x="11" y="-95.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- id : INTEGER</text>
+<text text-anchor="start" x="11" y="-84.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- recipient : VARCHAR</text>
+<text text-anchor="start" x="11" y="-73.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- isBilled : BOOLEAN</text>
+<text text-anchor="start" x="11" y="-62.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- date : DATETIME</text>
+<text text-anchor="start" x="11" y="-51.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- price : NUMERIC(8, 2)</text>
+<text text-anchor="start" x="11" y="-40.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- job : INTEGER</text>
+<text text-anchor="start" x="11" y="-29.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- offer : VARCHAR</text>
+</g>
+<!-- job -->
+<g id="node3" class="node"><title>job</title>
+<polygon fill="none" stroke="black" points="150.5,-75 150.5,-135 235.5,-135 235.5,-75 150.5,-75"/>
+<text text-anchor="start" x="187.5" y="-126.367" font-family="Bitstream-Vera Sans" font-size="7.00">job</text>
+<polygon fill="none" stroke="black" points="152,-120 152,-122 235,-122 235,-120 152,-120"/>
+<text text-anchor="start" x="154" y="-112.867" font-family="Bitstream-Vera Sans" font-size="7.00">- hash : VARCHAR</text>
+<text text-anchor="start" x="154" y="-101.867" font-family="Bitstream-Vera Sans" font-size="7.00">- info : VARCHAR</text>
+<text text-anchor="start" x="154" y="-90.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- status : VARCHAR(7)</text>
+<text text-anchor="start" x="154" y="-79.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- user : VARCHAR</text>
+</g>
+<!-- message->job -->
+<g id="edge2" class="edge"><title>message->job</title>
+<path fill="none" stroke="black" d="M106.327,-84.57C115.412,-86.7114 124.894,-88.9465 134.112,-91.1194"/>
+<ellipse fill="none" stroke="black" cx="138.236" cy="-92.0912" rx="4.00001" ry="4.00001"/>
+<text text-anchor="middle" x="132.338" y="-92.7431" font-family="Bitstream-Vera Sans" font-size="7.00">+ hash</text>
+<text text-anchor="middle" x="116.118" y="-80.2359" font-family="Bitstream-Vera Sans" font-size="7.00">+ job</text>
+</g>
+<!-- offer -->
+<g id="node5" class="node"><title>offer</title>
+<polygon fill="none" stroke="black" points="288,-4 288,-64 370,-64 370,-4 288,-4"/>
+<text text-anchor="start" x="320.5" y="-55.3667" font-family="Bitstream-Vera Sans" font-size="7.00">offer</text>
+<polygon fill="none" stroke="black" points="289,-49 289,-51 369,-51 369,-49 289,-49"/>
+<text text-anchor="start" x="291" y="-41.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- name : VARCHAR</text>
+<text text-anchor="start" x="291" y="-30.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- provider : VARCHAR</text>
+<text text-anchor="start" x="291" y="-19.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- route : VARCHAR</text>
+<text text-anchor="start" x="291" y="-8.86667" font-family="Bitstream-Vera Sans" font-size="7.00">- typ : VARCHAR</text>
+</g>
+<!-- message->offer -->
+<g id="edge4" class="edge"><title>message->offer</title>
+<path fill="none" stroke="black" d="M106.216,-64.6732C153.699,-58.1357 223.047,-48.5878 271.726,-41.8855"/>
+<ellipse fill="none" stroke="black" cx="275.694" cy="-41.3393" rx="4.00001" ry="4.00001"/>
+<text text-anchor="middle" x="271.255" y="-43.9165" font-family="Bitstream-Vera Sans" font-size="7.00">+ name</text>
+<text text-anchor="middle" x="114.618" y="-56.9504" font-family="Bitstream-Vera Sans" font-size="7.00">+ offer</text>
+</g>
+<!-- userright -->
+<g id="node2" class="node"><title>userright</title>
+<polygon fill="none" stroke="black" points="422.5,-46.5 422.5,-95.5 507.5,-95.5 507.5,-46.5 422.5,-46.5"/>
+<text text-anchor="start" x="448.5" y="-86.3667" font-family="Bitstream-Vera Sans" font-size="7.00">userright</text>
+<polygon fill="none" stroke="black" points="424,-80 424,-82 507,-82 507,-80 424,-80"/>
+<text text-anchor="start" x="426" y="-72.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- user : VARCHAR</text>
+<text text-anchor="start" x="426" y="-61.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- offer : VARCHAR</text>
+<text text-anchor="start" x="426" y="-50.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- isDefault : BOOLEAN</text>
+</g>
+<!-- apiuser -->
+<g id="node4" class="node"><title>apiuser</title>
+<polygon fill="none" stroke="black" points="291.5,-90 291.5,-128 366.5,-128 366.5,-90 291.5,-90"/>
+<text text-anchor="start" x="315.5" y="-119.367" font-family="Bitstream-Vera Sans" font-size="7.00">apiuser</text>
+<polygon fill="none" stroke="black" points="293,-113 293,-115 366,-115 366,-113 293,-113"/>
+<text text-anchor="start" x="295" y="-105.867" font-family="Bitstream-Vera Sans" font-size="7.00">- name : VARCHAR</text>
+<text text-anchor="start" x="295" y="-94.8667" font-family="Bitstream-Vera Sans" font-size="7.00">- apikey : VARCHAR</text>
+</g>
+<!-- job->apiuser -->
+<g id="edge10" class="edge"><title>job->apiuser</title>
+<path fill="none" stroke="black" d="M243.641,-106.489C253.891,-106.791 264.704,-107.109 275.063,-107.414"/>
+<ellipse fill="none" stroke="black" cx="279.255" cy="-107.537" rx="4" ry="4"/>
+<text text-anchor="middle" x="274.069" y="-109.312" font-family="Bitstream-Vera Sans" font-size="7.00">+ name</text>
+<text text-anchor="middle" x="252.825" y="-100.232" font-family="Bitstream-Vera Sans" font-size="7.00">+ user</text>
+</g>
+<!-- apiuser->userright -->
+<g id="edge6" class="edge"><title>apiuser->userright</title>
+<path fill="none" stroke="black" d="M374.664,-96.2408C387.32,-92.7048 401.136,-88.8443 414.071,-85.23"/>
+<text text-anchor="middle" x="406.48" y="-89.4392" font-family="Bitstream-Vera Sans" font-size="7.00">+ name</text>
+<text text-anchor="middle" x="382.256" y="-87.4316" font-family="Bitstream-Vera Sans" font-size="7.00">+ user</text>
+</g>
+<!-- offer->userright -->
+<g id="edge8" class="edge"><title>offer->userright</title>
+<path fill="none" stroke="black" d="M378.099,-47.3578C389.816,-50.5456 402.347,-53.9546 414.141,-57.1634"/>
+<text text-anchor="middle" x="404.286" y="-56.5621" font-family="Bitstream-Vera Sans" font-size="7.00">+ name</text>
+<text text-anchor="middle" x="387.954" y="-43.3591" font-family="Bitstream-Vera Sans" font-size="7.00">+ offer</text>
+</g>
+</g>
+</svg>
--- a/doc/impressum.html Sun Dec 18 11:49:12 2011 +0100
+++ b/doc/impressum.html Sun Dec 18 11:49:46 2011 +0100
@@ -19,7 +19,7 @@
<div id="head">
<h1 id="logo"><a href="index.html" class="logo" title="Netzguerilla"><span>Netzguerilla</span></a></h1>
<ul id="menu">
- <li><a href="index.html" class="menu">Iro</a></li><li><a href="current.html" class="menu">API Documentation</a></li><li><a href="new.html" class="menu">geplante API Documentation</a></li><li><a href="impressum.html" class="menu active">Impressum</a></li>
+ <li><a href="index.html" class="menu">Iro</a></li><li><a href="current.html" class="menu">API Documentation</a></li><li><a href="new.html" class="menu">geplante API Documentation</a></li><li><a href="database.html" class="menu">Datenbank Schema</a></li><li><a href="impressum.html" class="menu active">Impressum</a></li>
</ul>
</div>
</div>
--- a/doc/index.html Sun Dec 18 11:49:12 2011 +0100
+++ b/doc/index.html Sun Dec 18 11:49:46 2011 +0100
@@ -19,7 +19,7 @@
<div id="head">
<h1 id="logo"><a href="index.html" class="logo" title="Netzguerilla"><span>Netzguerilla</span></a></h1>
<ul id="menu">
- <li><a href="index.html" class="menu active">Iro</a></li><li><a href="current.html" class="menu">API Documentation</a></li><li><a href="new.html" class="menu">geplante API Documentation</a></li><li><a href="impressum.html" class="menu">Impressum</a></li>
+ <li><a href="index.html" class="menu active">Iro</a></li><li><a href="current.html" class="menu">API Documentation</a></li><li><a href="new.html" class="menu">geplante API Documentation</a></li><li><a href="database.html" class="menu">Datenbank Schema</a></li><li><a href="impressum.html" class="menu">Impressum</a></li>
</ul>
</div>
</div>
--- a/doc/new.html Sun Dec 18 11:49:12 2011 +0100
+++ b/doc/new.html Sun Dec 18 11:49:46 2011 +0100
@@ -19,7 +19,7 @@
<div id="head">
<h1 id="logo"><a href="index.html" class="logo" title="Netzguerilla"><span>Netzguerilla</span></a></h1>
<ul id="menu">
- <li><a href="index.html" class="menu">Iro</a></li><li><a href="current.html" class="menu">API Documentation</a></li><li><a href="new.html" class="menu active">geplante API Documentation</a></li><li><a href="impressum.html" class="menu">Impressum</a></li>
+ <li><a href="index.html" class="menu">Iro</a></li><li><a href="current.html" class="menu">API Documentation</a></li><li><a href="new.html" class="menu active">geplante API Documentation</a></li><li><a href="database.html" class="menu">Datenbank Schema</a></li><li><a href="impressum.html" class="menu">Impressum</a></li>
</ul>
</div>
</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tmpl/database.html Sun Dec 18 11:49:46 2011 +0100
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="layout.tmpl" />
+ <head>
+ <title>Datenbank</title>
+ </head>
+ <body>
+ <title>Datenbank Schema</title>
+ <div class="item">
+ <p>
+
+ </p>
+ <ol>
+ <li value="1">1. <a href="#schema">Datenbankschema</a></li>
+ <li value="3">3.
+ <a href="#tables">Tabellen</a>
+ <ol>
+ <li py:for="(key,table) in enumerate(tables)" value="2.${key+1}">2.${key+1} <a href="#table-${table.tablename}">${table.title}</a></li>
+ </ol>
+ </li>
+ </ol>
+ </div>
+
+
+ <div class="item" id="schema">
+ <h3>Schema</h3>
+ <img src="images/db-schema.svg" />
+ <p>Dies ist eine Übersicht der benutzen Tabellen die Iro benötigt.</p>
+ </div>
+ <div class="item" id="tables">
+ <h3>Tabellen</h3>
+ <div py:for="table in tables" class="item" id="table-${table.tablename}">
+ <h4>${table.title}</h4>
+ <p py:content="Markup(table.description)">
+ Dieser Tabelle fehlt noch die Beschreibung.
+ </p>
+ </div>
+ </div>
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/iro/schema.py Sun Dec 18 11:49:46 2011 +0100
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+
+from sqlalchemy import Column, Integer, String, Sequence, Boolean, DateTime, Numeric, Enum
+from sqlalchemy import create_engine
+from sqlalchemy.ext.declarative import declarative_base
+
+#relationship
+from sqlalchemy import ForeignKey
+from sqlalchemy.orm import relationship, backref
+
+engine = create_engine('sqlite:///:memory:', echo=True)
+Base = declarative_base()
+
+__tables__=["User", "Job", "Message", "Offer", "Userright"]
+
+class Userright(Base):
+ """Über welche Routen darf ein Benutzer Daten verschicken und welches sind die Standardrouten (<em>isDefault=1</em>) für den Benuter."""
+ __tablename__ = 'userright'
+ user_name = Column('user', String, ForeignKey('apiuser.name'), primary_key=True)
+ offer_name = Column('offer', String, ForeignKey('offer.name'), primary_key=True)
+ isDefault = Column(Boolean)
+ offer = relationship("Offer")
+
+class Offer(Base):
+ """Alle Routen über die SMS, Faxe und Mails verschickt werden könnnen. <em>provider</em>, <em>typ</em> und <em>route</em> werden verwendet, um die entsprechenden Zugangsdaten laden zu können."""
+ __tablename__ = "offer"
+ name = Column(String, primary_key=True)
+ provider = Column(String)
+ route = Column(String)
+ typ = Column(String)
+
+
+class Message(Base):
+ """Wenn ein Vorgang von Iro Kosten erzeugt hat wird eine neue Zeile eingefügt. Solange nicht bezahlt wurde ist <em>isBilled=0</em>."""
+ __tablename__ = "message"
+ id = Column(Integer, Sequence('message_id_seq'), primary_key=True)
+ recipient = Column(String)
+ isBilled = Column(Boolean)
+ date = Column(DateTime)
+ price = Column(Numeric(8,2))
+ job_hash = Column("job",Integer, ForeignKey('job.hash'))
+ job = relationship("Job", backref=backref('messages'))
+ offer_id = Column("offer",String, ForeignKey('offer.name'))
+ offer = relationship("Offer", backref=backref('messages'))
+
+
+class Job(Base):
+ """Ein kompletter Auftrag, der an Iro zum verschicken übergeben wird. Status zeigt den generellen Status des Auftrages an (<em>init</em>, <em>started</em>, <em>sending</em>, <em>sended</em> oder <em>error</em>). <em>info</em> wird verwendet um dem Benutzer eine Möglickeit zu geben verschiede Auftragsgruppen zu erstellen."""
+ __tablename__ = "job"
+ hash = Column(String, primary_key=True)
+ info = Column(String)
+ status = Column(Enum("init","started","sending","sended","error"))
+ user_id = Column("user", String, ForeignKey('apiuser.name'))
+ user = relationship("User", backref=backref('jobs'))
+
+class User(Base):
+ """Die Benutzerdatenbank von Iro."""
+ __tablename__ = "apiuser"
+ name = Column(String, primary_key=True)
+ apikey = Column(String,unique=True)
+ rights = relationship('Userright')
+ def __init__(self, name, apikey):
+ self.name=name
+ self.apikey=apikey
+
+ def __repr__(self):
+ return "<User('%s','%s')>"%(self.name,self.apikey)
+
+
+#Base.metadata.create_all(engine)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sqlalchemy_schemadisplay3.py Sun Dec 18 11:49:46 2011 +0100
@@ -0,0 +1,173 @@
+# updated SQLA schema display to work with pydot 1.0.2
+# download from: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SchemaDisplay
+
+
+from sqlalchemy.orm.properties import PropertyLoader
+import pydot
+import types
+
+__all__ = ['create_uml_graph', 'create_schema_graph', 'show_uml_graph', 'show_schema_graph']
+
+def _mk_label(mapper, show_operations, show_attributes, show_datatypes, bordersize):
+ html = '<<TABLE CELLSPACING="0" CELLPADDING="1" BORDER="0" CELLBORDER="%d" BALIGN="LEFT"><TR><TD><FONT POINT-SIZE="10">%s</FONT></TD></TR>' % (bordersize, mapper.class_.__name__)
+ def format_col(col):
+ colstr = '+%s' % (col.name)
+ if show_datatypes:
+ colstr += ' : %s' % (col.type.__class__.__name__)
+ return colstr
+
+ if show_attributes:
+ html += '<TR><TD ALIGN="LEFT">%s</TD></TR>' % '<BR ALIGN="LEFT"/>'.join(format_col(col) for col in sorted(mapper.columns, key=lambda col:not col.primary_key))
+ else:
+ [format_col(col) for col in sorted(mapper.columns, key=lambda col:not col.primary_key)]
+ if show_operations:
+ html += '<TR><TD ALIGN="LEFT">%s</TD></TR>' % '<BR ALIGN="LEFT"/>'.join(
+ '%s(%s)' % (name,", ".join(default is _mk_label and ("%s") % arg or ("%s=%s" % (arg,repr(default))) for default,arg in
+ zip((func.func_defaults and len(func.func_code.co_varnames)-1-(len(func.func_defaults) or 0) or func.func_code.co_argcount-1)*[_mk_label]+list(func.func_defaults or []), func.func_code.co_varnames[1:])
+ ))
+ for name,func in mapper.class_.__dict__.items() if isinstance(func, types.FunctionType) and func.__module__ == mapper.class_.__module__
+ )
+ html+= '</TABLE>>'
+ return html
+
+
+def create_uml_graph(mappers, show_operations=True, show_attributes=True, show_multiplicity_one=False, show_datatypes=True, linewidth=1.0, font="Bitstream-Vera Sans"):
+ graph = pydot.Dot(prog='neato',mode="major",overlap="0", sep="0.01",dim="3", pack="True", ratio=".75")
+ relations = set()
+ for mapper in mappers:
+ graph.add_node(pydot.Node(mapper.class_.__name__,
+ shape="plaintext", label=_mk_label(mapper, show_operations, show_attributes, show_datatypes, linewidth),
+ fontname=font, fontsize="8.0",
+ ))
+ if mapper.inherits:
+ graph.add_edge(pydot.Edge(mapper.inherits.class_.__name__,mapper.class_.__name__,
+ arrowhead='none',arrowtail='empty', style="setlinewidth(%s)" % linewidth, arrowsize=str(linewidth)))
+ for loader in mapper.iterate_properties:
+ if isinstance(loader, PropertyLoader) and loader.mapper in mappers:
+ if hasattr(loader, 'reverse_property'):
+ relations.add(frozenset([loader, loader.reverse_property]))
+ else:
+ relations.add(frozenset([loader]))
+
+ for relation in relations:
+ #if len(loaders) > 2:
+ # raise Exception("Warning: too many loaders for join %s" % join)
+ args = {}
+ def multiplicity_indicator(prop):
+ if prop.uselist:
+ return ' *'
+ if any(col.nullable for col in prop.local_side):
+ return ' 0..1'
+ if show_multiplicity_one:
+ return ' 1'
+ return ''
+
+ if len(relation) == 2:
+ src, dest = relation
+ from_name = src.parent.class_.__name__
+ to_name = dest.parent.class_.__name__
+
+ def calc_label(src,dest):
+ return '+' + src.key + multiplicity_indicator(src)
+ args['headlabel'] = calc_label(src,dest)
+
+ args['taillabel'] = calc_label(dest,src)
+ args['arrowtail'] = 'none'
+ args['arrowhead'] = 'none'
+ args['constraint'] = False
+ else:
+ prop, = relation
+ from_name = prop.parent.class_.__name__
+ to_name = prop.mapper.class_.__name__
+ args['headlabel'] = '+%s%s' % (prop.key, multiplicity_indicator(prop))
+ args['arrowtail'] = 'none'
+ args['arrowhead'] = 'vee'
+
+ graph.add_edge(pydot.Edge(from_name,to_name,
+ fontname=font, fontsize="7.0", style="setlinewidth(%s)"%linewidth, arrowsize=str(linewidth),
+ **args)
+ )
+
+ return graph
+
+#from sqlalchemy import Table, text
+
+def _render_table_html(table, metadata, show_indexes, show_datatypes):
+ def format_col_type(col):
+ try:
+ return col.type.get_col_spec()
+ except NotImplementedError:
+ return str(col.type)
+ except AttributeError:
+ return str(col.type)
+ def format_col_str(col):
+ if show_datatypes:
+ return "- %s : %s" % (col.name, format_col_type(col))
+ else:
+ return "- %s" % col.name
+ html = '<<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0"><TR><TD ALIGN="CENTER">%s</TD></TR><TR><TD BORDER="1" CELLPADDING="0"></TD></TR>' % table.name
+
+ html += ''.join('<TR><TD ALIGN="LEFT" PORT="%s">%s</TD></TR>' % (col.name, format_col_str(col)) for col in table.columns)
+ html += '</TABLE>>'
+ return html
+
+def create_schema_graph(tables=None, metadata=None, show_indexes=True, show_datatypes=True, font="Bitstream-Vera Sans",
+ concentrate=True, relation_options={}, rankdir='TB'):
+ relation_kwargs = {
+ 'fontsize':"7.0"
+ }
+ relation_kwargs.update(relation_options)
+
+ if not metadata and len(tables):
+ metadata = tables[0].metadata
+ elif not tables and metadata:
+ if not len(metadata.tables):
+ metadata.reflect()
+ tables = metadata.tables.values()
+ else:
+ raise Exception("You need to specify at least tables or metadata")
+
+ graph = pydot.Dot(prog="dot",mode="ipsep",overlap="ipsep",sep="0.01",concentrate=str(concentrate), rankdir=rankdir)
+ for table in tables:
+ graph.add_node(pydot.Node(str(table.name),
+ shape="plaintext",
+ label=_render_table_html(table, metadata, show_indexes, show_datatypes),
+ fontname=font, fontsize="7.0"
+ ))
+
+ for table in tables:
+ for fk in table.foreign_keys:
+ edge = [table.name, fk.column.table.name]
+ is_inheritance = fk.parent.primary_key and fk.column.primary_key
+ if is_inheritance:
+ edge = edge[::-1]
+ graph_edge = pydot.Edge(
+ headlabel="+ %s"%fk.column.name, taillabel='+ %s'%fk.parent.name,
+ arrowhead=is_inheritance and 'none' or 'odot' ,
+ arrowtail=(fk.parent.primary_key or fk.parent.unique) and 'empty' or 'crow' ,
+ fontname=font,
+ #samehead=fk.column.name, sametail=fk.parent.name,
+ *edge, **relation_kwargs
+ )
+ graph.add_edge(graph_edge)
+
+# not sure what this part is for, doesn't work with pydot 1.0.2
+# graph_edge.parent_graph = graph.parent_graph
+# if table.name not in [e.get_source() for e in graph.get_edge_list()]:
+# graph.edge_src_list.append(table.name)
+# if fk.column.table.name not in graph.edge_dst_list:
+# graph.edge_dst_list.append(fk.column.table.name)
+# graph.sorted_graph_elements.append(graph_edge)
+ return graph
+
+def show_uml_graph(*args, **kwargs):
+ from cStringIO import StringIO
+ from PIL import Image
+ iostream = StringIO(create_uml_graph(*args, **kwargs).create_png())
+ Image.open(iostream).show(command=kwargs.get('command','gwenview'))
+
+def show_schema_graph(*args, **kwargs):
+ from cStringIO import StringIO
+ from PIL import Image
+ iostream = StringIO(create_schema_graph(*args, **kwargs).create_png())
+ Image.open(iostream).show(command=kwargs.get('command','gwenview'))