Skip to content

Commit

Permalink
restructuring of utils
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Knupp committed Jan 7, 2014
1 parent dc02480 commit 86571dc
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 45 deletions.
2 changes: 1 addition & 1 deletion sandman/__init__.py
Expand Up @@ -10,4 +10,4 @@
db = SQLAlchemy(app)
from . import sandman

__version__ = '0.7.0'
__version__ = '0.7.2'
81 changes: 45 additions & 36 deletions sandman/model/utils.py
Expand Up @@ -12,7 +12,7 @@
from sandman import app, db
from sandman.model.models import Model, AdminModelViewWithPK

def generate_endpoint_classes():
def generate_endpoint_classes(db, generate_pks=False):
"""Return a list of model classes generated for each reflected database
table."""
seen_classes = set()
Expand All @@ -21,49 +21,52 @@ def generate_endpoint_classes():
for name, table in db.metadata.tables.items():
if not name in seen_classes:
seen_classes.add(name)
if not table.primary_key and current_app.config['SANDMAN_ALL_PRIMARY']:
cls = generate_primary_key(table)
if not table.primary_key and generate_pks:
cls = add_pk_if_required(db, table, name)
else:
cls = type(str(name), (sandman_model, db.Model),
{'__tablename__': name})
register(cls)

def generate_primary_key(table):
def add_pks_if_required(db, known_tables=None):
for name, table in db.metadata.tables.items():
if known_tables is None or table in known_tables:
cls = add_pk_if_required(db, table, name)
register(cls)

def add_pk_if_required(db, table, name):
"""Return a class deriving from our Model class as well as the SQLAlchemy
model.
:param `sqlalchemy.schema.Table` table: table to create primary key for
:param table: table to create primary key for
"""
with app.app_context():
db.metadata.reflect(bind=db.engine)
for name, table in db.metadata.tables.items():
cls_dict = {'__tablename__': name}
if not table.primary_key and current_app.config['SANDMAN_ALL_PRIMARY']:
for column in table.columns:
column.primary_key = True
Table(name, db.metadata, *table.columns, extend_existing=True)
cls_dict['__table__'] = table
db.metadata.create_all(bind=db.engine)

return type(str(name), (sandman_model, db.Model), cls_dict)

def prepare_relationships():
db.metadata.reflect(bind=db.engine)
cls_dict = {'__tablename__': name}
if not table.primary_key:
for column in table.columns:
column.primary_key = True
Table(name, db.metadata, *table.columns, extend_existing=True)
cls_dict['__table__'] = table
db.metadata.create_all(bind=db.engine)

return type(str(name), (sandman_model, db.Model), cls_dict)

def prepare_relationships(db, known_tables):
"""Enrich the registered Models with SQLAlchemy ``relationships``
so that related tables are correctly processed up by the admin.
"""
inspector = reflection.Inspector.from_engine(db.engine)
with app.app_context():
for cls in set(current_app.class_references.values()):
for foreign_key in inspector.get_foreign_keys(cls.__tablename__):
other = current_app.class_references[foreign_key['referred_table']]
if other not in cls.__related_tables__ and cls not in other.__related_tables__:
cls.__related_tables__.add(other)
# Add a SQLAlchemy relationship as an attribute on the class
if cls != other:
setattr(cls, other.__name__.lower(), relationship(
other.__name__, backref=cls.__name__.lower()))
for cls in set(known_tables.values()):
for foreign_key in inspector.get_foreign_keys(cls.__tablename__):
other = known_tables[foreign_key['referred_table']]
if other not in cls.__related_tables__ and cls not in other.__related_tables__ and other != cls:
cls.__related_tables__.add(other)
# Add a SQLAlchemy relationship as an attribute on the class
setattr(cls, other.__name__.lower(), relationship(
other.__name__, backref=cls.__name__.lower()))


def register(cls, use_admin=True):
Expand Down Expand Up @@ -110,8 +113,8 @@ def register_classes_for_admin(db_session, show_pks=True,
"""

admin_view = Admin(app, name=name)
with app.app_context():
admin_view = Admin(current_app, name=name)
for cls in set(cls for cls in current_app.class_references.values() if
cls.use_admin == True):
if show_pks:
Expand All @@ -138,17 +141,23 @@ def activate(admin=True, browser=True, name='admin'):
"""
with app.app_context():
if 'SANDMAN_SHOW_PKS' not in current_app.config:
current_app.config['SANDMAN_SHOW_PKS'] = False
if getattr(current_app, 'class_references', None) is None:
generate_endpoint_classes()
current_app.class_references = {}
try:
generate_pks = current_app.config['SANDMAN_GENERATE_PKS']
except KeyError:
generate_pks = False
generate_endpoint_classes(db, generate_pks)
else:
Model.prepare(db.engine)
prepare_relationships()
prepare_relationships(db, current_app.class_references)
if admin:
register_classes_for_admin(db.session,
current_app.config['SANDMAN_SHOW_PKS'] or False,
name)
try:
show_pks = current_app.config['SANDMAN_SHOW_PKS']
except KeyError:
show_pks = False
register_classes_for_admin(db.session, show_pks, name)
print current_app.url_map
if browser:
webbrowser.open('http://127.0.0.1:5000/admin')

Expand Down
14 changes: 7 additions & 7 deletions sandman/sandmanctl.py
@@ -1,7 +1,7 @@
"""Script to run sandman via command line
Usage:
sandmanctl.py URI [--primary-keys --all-columns-primary]
sandmanctl.py URI [--show-primary-keys --generate-pks]
Start sandman and connect to database at URI
Expand All @@ -27,9 +27,9 @@
Options:
-h --help Show this screen.
-p --primary-keys Display primary key columns in the admin
-s --show-primary-keys Display primary key columns in the admin
interface
-a --all-columns-primary Use the combination of all columns as the
-g --generate-pks Use the combination of all columns as the
primary key for tables without primary keys
(primary keys are required by the mapping
engine). Implies --primary-keys
Expand All @@ -49,11 +49,11 @@ def main(test_options=None):
"""Main entry point for script."""
options = test_options or docopt(__doc__)
app.config['SQLALCHEMY_DATABASE_URI'] = options['URI']
if '--all-columns-primary' in options:
app.config['SANDMAN_ALL_PRIMARY'] = True
if '--generate-pks' in options:
app.config['SANDMAN_GENERATE_PKS'] = True
app.config['SANDMAN_SHOW_PKS'] = True
else:
app.config['SANDMAN_ALL_PRIMARY'] = False
app.config['SANDMAN_SHOW_PKS'] = '--primary-keys' in options
app.config['SANDMAN_GENERATE_PKS'] = False
app.config['SANDMAN_SHOW_PKS'] = '--show-primary-keys' in options
activate(name='sandmanctl')
app.run('0.0.0.0', debug=True)
1 change: 0 additions & 1 deletion sandman/test/test_sandman.py
Expand Up @@ -6,7 +6,6 @@
import datetime

from sandman import app
from sandman.model import activate

class TestSandmanBase(object):
"""Base class for all sandman test classes."""
Expand Down

0 comments on commit 86571dc

Please sign in to comment.