changeset 173:e2a9b0c3d83e

Expose the database structure dump utility through the admin interface.
author Daniele Nicolodi <daniele@grinta.net>
date Sun, 06 Nov 2011 18:15:10 +0100
parents c690b879ddee
children 445540c83a43
files develop.cfg src/ltpdarepo/admin.py src/ltpdarepo/tests/dump.py src/ltpdarepo/tests/schema.py src/ltpdarepo/tests/test_schema.py src/setup.py
diffstat 6 files changed, 125 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/develop.cfg	Sun Nov 06 18:10:57 2011 +0100
+++ b/develop.cfg	Sun Nov 06 18:15:10 2011 +0100
@@ -8,7 +8,7 @@
      coverage
      zope.testbrowser [wsgi]
      SQLAlchemy
-scripts += unit2 coverage dump
+scripts += unit2 coverage
 
 [omelette]
 recipe = collective.recipe.omelette
--- a/src/ltpdarepo/admin.py	Sun Nov 06 18:10:57 2011 +0100
+++ b/src/ltpdarepo/admin.py	Sun Nov 06 18:15:10 2011 +0100
@@ -8,6 +8,12 @@
 
 import MySQLdb as mysql
 
+try:
+    import sqlalchemy
+    HAS_SQL_ALCHEMY = True
+except ImportError:
+    HAS_SQL_ALCHEMY = False
+
 from . import app
 app.config.from_pyfile('config.py')
 
@@ -92,6 +98,19 @@
 cmd.add_argument('--to', type=float, dest='_to', metavar='REV')
 
 
+if HAS_SQL_ALCHEMY:
+    from .tests import schema
+
+    def dump(database, tables=None, out=sys.stdout):
+        """dump database structure text representation"""
+
+        schema.dump(USERNAME, PASSWORD, HOSTNAME, database, tables=tables, out=out)
+
+    cmd = commands.add(dump)
+    cmd.add_argument('database')
+    cmd.add_argument('--tables', nargs='+')
+
+
 def useradd(username, password=None, **kwargs):
     """create user account"""
 
@@ -285,7 +304,7 @@
         description = random.choice(sentences)
         analysis = random.choice(sentences)
         submitted = datetime.utcnow() - timedelta(days=random.randint(0, nobjs / 10.0))
-        
+
         curs.execute("""INSERT INTO objs (xml, uuid) VALUES (%s, %s)""",
                      ('<?xml version="1.0" encoding="UTF-8" standalone="no"?>', str(uuid.uuid4())))
         objid = curs.lastrowid
@@ -301,7 +320,7 @@
                       submitted, title, description, analysis, 'FOO', '', '', 'testing', '',
                       None, None, None))
         curs.execute("""INSERT INTO ao (obj_id, data_type, description)
-                        VALUES (%s, %s, %s)""", (objid, 'tsdata', 'Foo'))        
+                        VALUES (%s, %s, %s)""", (objid, 'tsdata', 'Foo'))
         curs.execute("""INSERT INTO tsdata (obj_id, fs, t0, nsecs)
                         VALUES (%s, %s, %s, %s)""", (objid, 10, t0, nsecs))
         t0 += timedelta(seconds=nsecs)
--- a/src/ltpdarepo/tests/dump.py	Sun Nov 06 18:10:57 2011 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-from contextlib import contextmanager
-from cStringIO import StringIO
-
-import sqlalchemy
-
-
-class Formatter(object):
-    def __init__(self, out):
-        self.level = 0
-        self.out = out
-
-    @contextmanager
-    def indent(self, increase=1):
-        self.level += increase
-        yield
-        self.level -= increase
-
-    def write(self, string):
-        self.out.write('  ' * self.level)
-        self.out.write(string)
-        self.out.write('\n')
-
-
-def dump_schema(username, password, hostname, database, out):
-    f = Formatter(out)
-    url = sqlalchemy.engine.url.URL('mysql', username=username, password=password, host=hostname, database=database)
-    engine = sqlalchemy.engine.create_engine(url)
-    inspector = sqlalchemy.engine.reflection.Inspector.from_engine(engine)
-    dump_database(inspector, f)
-
-
-def dump_database(inspector, f):
-    f.write(inspector.default_schema_name)
-    with f.indent():
-        # tables
-        for table in sorted(inspector.get_table_names()):
-            f.write('table: %s' % table)
-            with f.indent():
-                dump_table(inspector, table, f)
-        # views
-        for view in sorted(inspector.get_view_names()):
-            f.write('view: %s' % view)
-            with f.indent():
-                dump_table(inspector, view, f)
-
-
-def dump_table(inspector, table, f):
-    # columns
-    f.write('columns:')
-    with f.indent():
-        for column in sorted(inspector.get_columns(table)):
-            f.write('- %s' % column.pop('name'))
-            with f.indent():
-                for k, v in column.iteritems():
-                    f.write('%s: %s' % (k, v))
-    # primary keys
-    pks = inspector.get_primary_keys(table)
-    if pks:
-        f.write('primary keys:')
-        with f.indent():
-            for pk in pks:
-                f.write('- %s' % pk)
-    # foreign keys
-    fks = inspector.get_foreign_keys(table)
-    if fks:
-        f.write('foreign keys:')
-        with f.indent():
-            for fk in fks:
-                f.write('- %s' % fk.pop('name'))
-                fk.pop('options')
-                with f.indent():
-                    for k, v in fk.iteritems():
-                        if isinstance(v, list):
-                            v = ', '.join(map(unicode, v))
-                        f.write('%s: %s' % (k, v))
-    # indexes
-    indexes = inspector.get_indexes(table)
-    if indexes:
-        f.write('indexes:')
-        with f.indent():
-            for index in indexes:
-                f.write('- %s' % index.pop('name'))
-                with f.indent():
-                    for k, v in index.iteritems():
-                        if isinstance(v, list):
-                            v = ', '.join(map(unicode, v))
-                        f.write('%s: %s' % (k, v))
-    # options
-    options = inspector.get_table_options(table)
-    if options:
-        f.write('options:')
-        with f.indent():
-            for k, v in options.iteritems():
-                if k.startswith('mysql_'):
-                    k = k[6:]
-                f.write('- %s: %s' % (k, v))
-
-
-def main():
-    import sys
-    username, password, hostname, database = sys.argv[1:]
-    dump_schema(username, password, hostname, database, sys.stdout)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ltpdarepo/tests/schema.py	Sun Nov 06 18:15:10 2011 +0100
@@ -0,0 +1,97 @@
+from contextlib import contextmanager
+from cStringIO import StringIO
+
+import sqlalchemy
+
+
+class Formatter(object):
+    def __init__(self, out):
+        self.level = 0
+        self.out = out
+
+    @contextmanager
+    def indent(self, increase=1):
+        self.level += increase
+        yield
+        self.level -= increase
+
+    def write(self, string):
+        self.out.write('  ' * self.level)
+        self.out.write(string)
+        self.out.write('\n')
+
+
+def dump(username, password, hostname, database, tables=None, out=None):
+    f = Formatter(out)
+    url = sqlalchemy.engine.url.URL('mysql',
+                                    username=username, password=password,
+                                    host=hostname, database=database)
+    engine = sqlalchemy.engine.create_engine(url)
+    inspector = sqlalchemy.engine.reflection.Inspector.from_engine(engine)
+    _dump_database_tables(inspector, tables, f)
+
+
+def _dump_database_tables(inspector, tables, f):
+    f.write(inspector.default_schema_name)
+    with f.indent():
+        if tables is None:
+            tables = sorted(inspector.get_table_names() + inspector.get_view_names())        
+        for table in tables:
+            if table in inspector.get_view_names():
+                f.write('view: %s' % table)
+            else:
+                f.write('table: %s' % table)
+            with f.indent():
+                _dump_table_structure(inspector, table, f)
+
+
+def _dump_table_structure(inspector, table, f):
+    # columns
+    f.write('columns:')
+    with f.indent():
+        for column in sorted(inspector.get_columns(table)):
+            f.write('- %s' % column.pop('name'))
+            with f.indent():
+                for k, v in column.iteritems():
+                    f.write('%s: %s' % (k, v))
+    # primary keys
+    pks = inspector.get_primary_keys(table)
+    if pks:
+        f.write('primary keys:')
+        with f.indent():
+            for pk in pks:
+                f.write('- %s' % pk)
+    # foreign keys
+    fks = inspector.get_foreign_keys(table)
+    if fks:
+        f.write('foreign keys:')
+        with f.indent():
+            for fk in fks:
+                f.write('- %s' % fk.pop('name'))
+                fk.pop('options')
+                with f.indent():
+                    for k, v in fk.iteritems():
+                        if isinstance(v, list):
+                            v = ', '.join(map(unicode, v))
+                        f.write('%s: %s' % (k, v))
+    # indexes
+    indexes = inspector.get_indexes(table)
+    if indexes:
+        f.write('indexes:')
+        with f.indent():
+            for index in indexes:
+                f.write('- %s' % index.pop('name'))
+                with f.indent():
+                    for k, v in index.iteritems():
+                        if isinstance(v, list):
+                            v = ', '.join(map(unicode, v))
+                        f.write('%s: %s' % (k, v))
+    # options
+    options = inspector.get_table_options(table)
+    if options:
+        f.write('options:')
+        with f.indent():
+            for k, v in options.iteritems():
+                if k.startswith('mysql_'):
+                    k = k[6:]
+                f.write('- %s: %s' % (k, v))
--- a/src/ltpdarepo/tests/test_schema.py	Sun Nov 06 18:10:57 2011 +0100
+++ b/src/ltpdarepo/tests/test_schema.py	Sun Nov 06 18:15:10 2011 +0100
@@ -9,8 +9,7 @@
 import MySQLdb as mysql
 
 from ltpdarepo.config import USERNAME, PASSWORD, HOSTNAME
-from ltpdarepo.admin import wipe, install, createdb, useradd, grant, upgrade
-from ltpdarepo.tests.dump import dump_schema
+from ltpdarepo.admin import wipe, install, createdb, useradd, grant, upgrade, dump
 
 
 class TestCase(unittest.TestCase):
@@ -55,8 +54,8 @@
 
         # dump database structure
         upgraded = StringIO()
-        dump_schema(USERNAME, PASSWORD, HOSTNAME, 'ltpda', upgraded)
-        dump_schema(USERNAME, PASSWORD, HOSTNAME, 'db1', upgraded)
+        dump('ltpda', out=upgraded)
+        dump('db1', out=upgraded)
         upgraded.seek(0)
 
         # install
@@ -69,8 +68,8 @@
 
         # dump database structure
         new = StringIO()
-        dump_schema(USERNAME, PASSWORD, HOSTNAME, 'ltpda', new)
-        dump_schema(USERNAME, PASSWORD, HOSTNAME, 'db1', new)
+        dump('ltpda', out=new)
+        dump('db1', out=new)
         new.seek(0)
 
         # compare
--- a/src/setup.py	Sun Nov 06 18:10:57 2011 +0100
+++ b/src/setup.py	Sun Nov 06 18:15:10 2011 +0100
@@ -6,6 +6,5 @@
     name='ltpdarepo',
     version=VERSION,
     entry_points={'console_scripts': ['run = ltpdarepo:main',
-                                      'admin = ltpdarepo.admin:main',
-                                      'dump = ltpdarepo.tests.dump:main']}
+                                      'admin = ltpdarepo.admin:main',]}
 )