From 1592fd0419f374de201926d3ba67fbf1522eed13 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Fri, 27 Oct 2017 00:08:24 -0700 Subject: [PATCH] Started work on cli, which also meant adding setup.py I'm using click, and click recommends using a setup.py - so I've added one of those. I also refactored code into a new datasite package. It's not quite deploying to now properly at the moment though - I seem to have messed up the path handling a bit. Also snuck in a new template for the "Row" view. Refs #40 --- Dockerfile | 6 ++-- datasite/__init__.py | 0 app.py => datasite/app.py | 26 +++++++------- datasite/cli.py | 24 +++++++++++++ {templates => datasite/templates}/base.html | 0 .../templates}/database.html | 0 {templates => datasite/templates}/index.html | 0 datasite/templates/row.html | 35 +++++++++++++++++++ {templates => datasite/templates}/table.html | 0 setup.py | 18 ++++++++++ 10 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 datasite/__init__.py rename app.py => datasite/app.py (96%) create mode 100644 datasite/cli.py rename {templates => datasite/templates}/base.html (100%) rename {templates => datasite/templates}/database.html (100%) rename {templates => datasite/templates}/index.html (100%) create mode 100644 datasite/templates/row.html rename {templates => datasite/templates}/table.html (100%) create mode 100644 setup.py diff --git a/Dockerfile b/Dockerfile index fc10c98d..7a1d4b6f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM python:3 COPY . /app WORKDIR /app -RUN pip install -r requirements.txt -RUN python app.py --build +RUN pip install . +RUN datasite build EXPOSE 8006 -CMD ["python", "app.py"] +CMD ["datasite", "serve", "--port", "8006"] diff --git a/datasite/__init__.py b/datasite/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app.py b/datasite/app.py similarity index 96% rename from app.py rename to datasite/app.py index c90333ef..52ecea19 100644 --- a/app.py +++ b/datasite/app.py @@ -3,6 +3,8 @@ from sanic import response from sanic.exceptions import NotFound from sanic.views import HTTPMethodView from sanic_jinja2 import SanicJinja2 +from jinja2 import FileSystemLoader +import click import sqlite3 from contextlib import contextmanager from pathlib import Path @@ -14,7 +16,7 @@ import hashlib import sys import time -app_root = Path(__file__).parent +app_root = Path(__file__).parent.parent BUILD_METADATA = 'build-metadata.json' DB_GLOBS = ('*.db', '*.sqlite', '*.sqlite3') @@ -25,7 +27,12 @@ conns = {} app = Sanic(__name__) -jinja = SanicJinja2(app) +jinja = SanicJinja2( + app, + loader=FileSystemLoader([ + str(app_root / 'datasite' / 'templates') + ]) +) def get_conn(name): @@ -43,10 +50,12 @@ def get_conn(name): def ensure_build_metadata(regenerate=False): build_metadata = app_root / BUILD_METADATA if build_metadata.exists() and not regenerate: - json.loads(build_metadata.read_text()) + return json.loads(build_metadata.read_text()) + print('Building metadata... path={}'.format(build_metadata)) metadata = {} for glob in DB_GLOBS: for path in app_root.glob(glob): + print(' globbing, path={}'.format(path)) name = path.stem if name in metadata: raise Exception('Multiple files with same stem %s' % name) @@ -154,7 +163,7 @@ class BaseView(HTTPMethodView): @app.route('/') async def index(request, sql=None): databases = [] - for key, info in ensure_build_metadata(True).items(): + for key, info in ensure_build_metadata().items(): database = { 'name': key, 'hash': info['hash'], @@ -246,7 +255,7 @@ class TableView(BaseView): class RowView(BaseView): - template = 'table.html' + template = 'row.html' def data(self, request, name, hash, table, pk_path): conn = get_conn(name) @@ -409,10 +418,3 @@ def sqlite_timelimit(conn, ms): conn.set_progress_handler(handler, 10000) yield conn.set_progress_handler(None, 10000) - - -if __name__ == '__main__': - if '--build' in sys.argv: - ensure_build_metadata(True) - else: - app.run(host="0.0.0.0", port=8006) diff --git a/datasite/cli.py b/datasite/cli.py new file mode 100644 index 00000000..84c13dea --- /dev/null +++ b/datasite/cli.py @@ -0,0 +1,24 @@ +import click +from .app import app, ensure_build_metadata + +@click.group() +def cli(): + """ + Datasite! + """ + + +@cli.command() +def build(): + ensure_build_metadata(True) + + +@cli.command() +@click.argument('files', type=click.Path(exists=True), nargs=-1) +@click.option('-h', '--host', default='0.0.0.0') +@click.option('-p', '--port', default=8001) +@click.option('--debug', is_flag=True) +def serve(files, host, port, debug): + '''Serve up specified database files with a web UI''' + click.echo('Serve! files={} on port {}'.format(files, port)) + app.run(host=host, port=port, debug=debug) diff --git a/templates/base.html b/datasite/templates/base.html similarity index 100% rename from templates/base.html rename to datasite/templates/base.html diff --git a/templates/database.html b/datasite/templates/database.html similarity index 100% rename from templates/database.html rename to datasite/templates/database.html diff --git a/templates/index.html b/datasite/templates/index.html similarity index 100% rename from templates/index.html rename to datasite/templates/index.html diff --git a/datasite/templates/row.html b/datasite/templates/row.html new file mode 100644 index 00000000..b8ba00b8 --- /dev/null +++ b/datasite/templates/row.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} + +{% block title %}{{ database }}: {{ table }}{% endblock %} + +{% block content %} +

{{ database }}

+ +

{{ table }}

+ + + + + {% if primary_keys and row_link %}{% endif %} + {% for column in columns %}{% endfor %} + + {% for row in rows %} + + {% if primary_keys and row_link %} + + {% endif %} + {% for td in row %} + + {% endfor %} + + {% endfor %} +
Link{{ column }}
{{ row_link(row) }}{{ td }}
+{% if took_ms %}Took {{ took_ms }}{% endif %} +{% endblock %} diff --git a/templates/table.html b/datasite/templates/table.html similarity index 100% rename from templates/table.html rename to datasite/templates/table.html diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..0ce515d5 --- /dev/null +++ b/setup.py @@ -0,0 +1,18 @@ +from setuptools import setup, find_packages + +setup( + name='datasite', + version='0.1', + packages=find_packages(), + package_data={'datasite': ['templates/*.html']}, + include_package_data=True, + install_requires=[ + 'click==6.7', + 'sanic==0.6.0', + 'sanic-jinja2==0.5.5', + ], + entry_points=''' + [console_scripts] + datasite=datasite.cli:cli + ''', +)