|
{ |
|
"cells": [ |
|
{ |
|
"cell_type": "markdown", |
|
"metadata": {}, |
|
"source": [ |
|
"# Running Datasette in IPython" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"import os, datasette.app, datasette.cli, uvicorn, asyncio, IPython, sqlite3\n", |
|
"from pathlib import Path\n", |
|
"from jupyter_server.serverapp import ServerApp, web, ioloop\n", |
|
"from notebook.base.handlers import IPythonHandler\n", |
|
"from traitlets.config import LoggingConfigurable \n", |
|
"import socket\n", |
|
"import ipywidgets" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"def get_unused_port():\n", |
|
" \"\"\" Get an unused port by trying to listen to any random port.\n", |
|
" Probably could introduce race conditions if inside a tight loop.\n", |
|
" \"\"\"\n", |
|
" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n", |
|
" sock.bind((\"localhost\", 0))\n", |
|
" sock.listen(1)\n", |
|
" port = sock.getsockname()[1]\n", |
|
" sock.close()\n", |
|
" return port" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"class IDatasette(datasette.app.Datasette):\n", |
|
" pass" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"def make_a_datasette_server(files, app_args=None, prefix=None, port=None, start=True, proxy=False):\n", |
|
" app_args = app_args or {}\n", |
|
" uvi_args = dict(port=port or get_unused_port())\n", |
|
" \n", |
|
" if prefix is None:\n", |
|
" prefix = os.environ.get(\"JUPYTERHUB_SERVICE_PREFIX\")\n", |
|
" if prefix and proxy:\n", |
|
" prefix += f\"proxy/{port}/\"\n", |
|
" \n", |
|
" if prefix is None:\n", |
|
" prefix = \"/\"\n", |
|
" if proxy:\n", |
|
" prefix += f\"proxy/{port}/\"\n", |
|
" \n", |
|
" app_args.update(config=dict(base_url=prefix))\n", |
|
" app = IDatasette(files=files, **app_args)\n", |
|
" config = uvicorn.Config(app.app(), **uvi_args)\n", |
|
" server = uvicorn.Server(config=config)\n", |
|
" task = None\n", |
|
" if start:\n", |
|
" task = asyncio.ensure_future(server.serve())\n", |
|
" return app, server, task" |
|
] |
|
}, |
|
{ |
|
"cell_type": "markdown", |
|
"metadata": {}, |
|
"source": [ |
|
"From [the python docs](https://docs.python.org/3/library/sqlite3.html)." |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"def make_a_stocks_database():\n", |
|
" stocks = Path(\"stocks.sqlite\")\n", |
|
" stocks.exists() and stocks.unlink()\n", |
|
" conn = sqlite3.connect(stocks)\n", |
|
" c = conn.cursor()\n", |
|
" c.execute(\"\"\"\n", |
|
" CREATE TABLE stocks\n", |
|
" (date text, trans text, symbol text, qty real, price real)\n", |
|
" \"\"\")\n", |
|
" c.execute(\"INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)\")\n", |
|
" conn.commit()\n", |
|
" conn.close()\n", |
|
" return stocks" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"def make_a_datasette_control_panel(app, server):\n", |
|
" start = ipywidgets.Button(icon=\"play\", description=\"Start\", button_style=\"primary\")\n", |
|
" start.on_click(lambda _: ioloop.IOLoop.current().add_callback(server.serve))\n", |
|
" shutdown = ipywidgets.Button(icon=\"trash\", description=\"Shutdown\", button_style=\"danger\")\n", |
|
" shutdown.on_click(lambda _: ioloop.IOLoop.current().add_callback(server.shutdown))\n", |
|
" return ipywidgets.HBox([\n", |
|
" start,\n", |
|
" shutdown,\n", |
|
" ipywidgets.HTML(f\"\"\"\n", |
|
" <a href=\"{app.config(\"base_url\")}\">Datasette</a>\n", |
|
" \"\"\")\n", |
|
" ])" |
|
] |
|
}, |
|
{ |
|
"cell_type": "code", |
|
"execution_count": null, |
|
"metadata": {}, |
|
"outputs": [], |
|
"source": [ |
|
"if __name__ == \"__main__\":\n", |
|
" stocks = make_a_stocks_database()\n", |
|
" app, server, _ = make_a_datasette_server([stocks], port=8000, proxy=True, start=False)\n", |
|
" ui = make_a_datasette_control_panel(app, server)\n", |
|
" IPython.display.display(ui)" |
|
] |
|
} |
|
], |
|
"metadata": { |
|
"kernelspec": { |
|
"display_name": "Python 3", |
|
"language": "python", |
|
"name": "python3" |
|
}, |
|
"language_info": { |
|
"codemirror_mode": { |
|
"name": "ipython", |
|
"version": 3 |
|
}, |
|
"file_extension": ".py", |
|
"mimetype": "text/x-python", |
|
"name": "python", |
|
"nbconvert_exporter": "python", |
|
"pygments_lexer": "ipython3", |
|
"version": "3.8.6" |
|
} |
|
}, |
|
"nbformat": 4, |
|
"nbformat_minor": 4 |
|
} |