Refactored everything into a factory function

I now call a factory function to construct the Sanic app:

    app = app_factory(files)

This allows me to pass additional arguments to it, e.g. the files to serve.

Also refactored my class-based views to accept jinja as an argument, e.g:

    app.add_route(
        TableView.as_view(jinja),
        '/<db_name:[^/]+>/<table:[^/]+?><as_json:(.jsono?)?$>'
    )
This commit is contained in:
Simon Willison 2017-11-04 19:13:44 -07:00
commit 1fc75809a6
2 changed files with 61 additions and 41 deletions

View file

@ -25,15 +25,6 @@ SQL_TIME_LIMIT_MS = 1000
conns = {} conns = {}
app = Sanic(__name__)
jinja = SanicJinja2(
app,
loader=FileSystemLoader([
str(app_root / 'datasite' / 'templates')
])
)
def get_conn(name): def get_conn(name):
if name not in conns: if name not in conns:
info = ensure_build_metadata()[name] info = ensure_build_metadata()[name]
@ -89,6 +80,9 @@ def ensure_build_metadata(regenerate=False):
class BaseView(HTTPMethodView): class BaseView(HTTPMethodView):
template = None template = None
def __init__(self, jinja):
self.jinja = jinja
def redirect(self, request, path): def redirect(self, request, path):
if request.query_string: if request.query_string:
path = '{}?{}'.format( path = '{}?{}'.format(
@ -147,7 +141,7 @@ class BaseView(HTTPMethodView):
if callable(extra_template_data) if callable(extra_template_data)
else extra_template_data else extra_template_data
)} )}
r = jinja.render( r = self.jinja.render(
self.template, self.template,
request, request,
**context, **context,
@ -159,32 +153,34 @@ class BaseView(HTTPMethodView):
return r return r
@app.route('/') class IndexView(HTTPMethodView):
async def index(request, sql=None): def __init__(self, jinja):
databases = [] self.jinja = jinja
for key, info in ensure_build_metadata().items():
database = { async def get(self, request):
'name': key, databases = []
'hash': info['hash'], for key, info in ensure_build_metadata().items():
'path': '{}-{}'.format(key, info['hash'][:7]), database = {
'tables_truncated': sorted( 'name': key,
info['tables'].items(), 'hash': info['hash'],
key=lambda p: p[1], 'path': '{}-{}'.format(key, info['hash'][:7]),
reverse=True 'tables_truncated': sorted(
)[:5], info['tables'].items(),
'tables_count': len(info['tables'].items()), key=lambda p: p[1],
'tables_more': len(info['tables'].items()) > 5, reverse=True
'total_rows': sum(info['tables'].values()), )[:5],
} 'tables_count': len(info['tables'].items()),
databases.append(database) 'tables_more': len(info['tables'].items()) > 5,
return jinja.render( 'total_rows': sum(info['tables'].values()),
'index.html', }
request, databases.append(database)
databases=databases, return self.jinja.render(
) 'index.html',
request,
databases=databases,
)
@app.route('/favicon.ico')
async def favicon(request): async def favicon(request):
return response.text('') return response.text('')
@ -286,12 +282,6 @@ class RowView(BaseView):
} }
app.add_route(DatabaseView.as_view(), '/<db_name:[^/\.]+?><as_json:(.jsono?)?$>')
app.add_route(DatabaseDownload.as_view(), '/<db_name:[^/]+?><as_db:(\.db)$>')
app.add_route(TableView.as_view(), '/<db_name:[^/]+>/<table:[^/]+?><as_json:(.jsono?)?$>')
app.add_route(RowView.as_view(), '/<db_name:[^/]+>/<table:[^/]+?>/<pk_path:[^/]+?><as_json:(.jsono?)?$>')
def resolve_db_name(db_name, **kwargs): def resolve_db_name(db_name, **kwargs):
databases = ensure_build_metadata() databases = ensure_build_metadata()
hash = None hash = None
@ -418,3 +408,32 @@ def sqlite_timelimit(conn, ms):
conn.set_progress_handler(handler, 10000) conn.set_progress_handler(handler, 10000)
yield yield
conn.set_progress_handler(None, 10000) conn.set_progress_handler(None, 10000)
def app_factory(files):
app = Sanic(__name__)
jinja = SanicJinja2(
app,
loader=FileSystemLoader([
str(app_root / 'datasite' / 'templates')
])
)
app.add_route(IndexView.as_view(jinja), '/')
app.add_route(favicon, '/favicon.ico')
app.add_route(
DatabaseView.as_view(jinja),
'/<db_name:[^/\.]+?><as_json:(.jsono?)?$>'
)
app.add_route(
DatabaseDownload.as_view(jinja),
'/<db_name:[^/]+?><as_db:(\.db)$>'
)
app.add_route(
TableView.as_view(jinja),
'/<db_name:[^/]+>/<table:[^/]+?><as_json:(.jsono?)?$>'
)
app.add_route(
RowView.as_view(jinja),
'/<db_name:[^/]+>/<table:[^/]+?>/<pk_path:[^/]+?><as_json:(.jsono?)?$>'
)
return app

View file

@ -1,6 +1,6 @@
import click import click
from click_default_group import DefaultGroup from click_default_group import DefaultGroup
from .app import app, ensure_build_metadata from .app import app_factory, ensure_build_metadata
@click.group(cls=DefaultGroup, default='serve', default_if_no_args=True) @click.group(cls=DefaultGroup, default='serve', default_if_no_args=True)
@ -23,4 +23,5 @@ def build():
def serve(files, host, port, debug): def serve(files, host, port, debug):
"""Serve up specified database files with a web UI""" """Serve up specified database files with a web UI"""
click.echo('Serve! files={} on port {}'.format(files, port)) click.echo('Serve! files={} on port {}'.format(files, port))
app = app_factory(files)
app.run(host=host, port=port, debug=debug) app.run(host=host, port=port, debug=debug)