Mercurial > hg > ltpdarepo
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',]} )