diff --git a/README.md b/README.md index e159297..04975d4 100644 --- a/README.md +++ b/README.md @@ -11,25 +11,36 @@ Periodically refresh Datasette metadata from a remote URL Install this plugin in the same environment as Datasette. - $ datasette install datasette-remote-metadata +```bash +datasette install datasette-remote-metadata +``` ## Usage -Add the following to your `metadata.json`: +Add the following to your `datasette.yml`: -```json -{ - "plugins": { - "datasette-remote-metadata": { - "url": "https://example.com/remote-metadata.yml" - } - } -} +```yaml +plugins: + datasette-remote-metadata: + url: "https://example.com/remote-metadata.yml" ``` + +Then start Datasette like this: +```bash +datasette mydatabase.db -c datasette.yml +``` + The plugin will fetch the specified metadata from that URL at startup and combine it with any existing metadata. You can use a URL to either a JSON file or a YAML file. It will periodically refresh that metadata - by default every 30 seconds, unless you specify an alternative `"ttl"` value in the plugin configuration. +You can also use the `datasette -s` option to configure the plugin without a configuration file: +```bash +datasette \ + -s plugins.datasette-remote-metadata.url 'https://example.com/remote-metadata.yml' \ + -s plugins.datasette-remote-metadata.ttl 2 \ + mydatabase.db +``` ## Configuration Available configuration options are as follows: @@ -39,49 +50,50 @@ Available configuration options are as follows: - `"headers"` - a dictionary of additional request headers to send. - `"cachebust"` - if true, a random `?0.29508` value will be added to the query string of the remote metadata to bust any intermediary caches. -This example `metadata.json` configuration refreshes every 10 seconds, uses cache busting and sends an `Authorization: Bearer xyz` header with the request: +This example `datasette.yml` configuration refreshes every 10 seconds, uses cache busting and sends an `Authorization: Bearer xyz` header with the request: -```json -{ - "plugins": { - "datasette-remote-metadata": { - "url": "https://example.com/remote-metadata.yml", - "ttl": 10, - "cachebust": true, - "headers": { - "Authorization": "Bearer xyz" - } - } - } -} -``` -This example if you are using `metadata.yaml` for configuration: ```yaml plugins: datasette-remote-metadata: - url: https://example.com/remote-metadata.yml + url: "https://example.com/remote-metadata.yml" ttl: 10 cachebust: true headers: - Authorization: Bearer xyz + Authorization: "Bearer xyz" +``` +This example if you are using `datasette.json` for configuration: +```json +{ + "plugins": { + "datasette-remote-metadata": { + "url": "https://example.com/remote-metadata.yml", + "ttl": 10, + "cachebust": true, + "headers": { + "Authorization": "Bearer xyz" + } + } + } +} ``` ## Development To set up this plugin locally, first checkout the code. Then create a new virtual environment: - - cd datasette-remote-metadata - python3 -mvenv venv - source venv/bin/activate - +```bash +cd datasette-remote-metadata +python3 -mvenv venv +source venv/bin/activate +``` Or if you are using `pipenv`: - - pipenv shell - +```bash +pipenv shell +``` Now install the dependencies and test dependencies: - - pip install -e '.[test]' - +```bash +pip install -e '.[test]' +``` To run the tests: - - pytest +```bash +pytest +``` \ No newline at end of file diff --git a/datasette_remote_metadata/__init__.py b/datasette_remote_metadata/__init__.py index e49cd0a..701eb38 100644 --- a/datasette_remote_metadata/__init__.py +++ b/datasette_remote_metadata/__init__.py @@ -30,7 +30,7 @@ async def update_remote(): ) response.raise_for_status() metadata = parse_metadata(response.content) - datasette._remote_metadata = metadata + await apply_metadata(datasette, metadata) datasette._remote_metadata_last_updated = time.monotonic() if timelimit is not None: @@ -45,16 +45,12 @@ async def update_remote(): @hookimpl def startup(datasette): async def inner(): + await datasette.refresh_schemas() await update_remote_with_time_limit(datasette) return inner -@hookimpl -def get_metadata(datasette): - return getattr(datasette, "_remote_metadata", None) or {} - - @hookimpl def asgi_wrapper(datasette): # Refresh stale (over X seconds old) remote metadata on every request @@ -72,3 +68,31 @@ async def add_refresh(scope, recieve, send): return add_refresh return wrap_with_refresh + + +# Imitating https://github.com/simonw/datasette/blob/f6bd2bf8/datasette/app.py#L446-L472 +async def apply_metadata(datasette, metadata_dict): + for key in metadata_dict or {}: + if key == "databases": + continue + await datasette.set_instance_metadata(key, metadata_dict[key]) + + # database-level + for dbname, db in metadata_dict.get("databases", {}).items(): + for key, value in db.items(): + if key == "tables": + continue + await datasette.set_database_metadata(dbname, key, value) + + # table-level + for tablename, table in db.get("tables", {}).items(): + for key, value in table.items(): + if key == "columns": + continue + await datasette.set_resource_metadata(dbname, tablename, key, value) + + # column-level + for columnname, column_description in table.get("columns", {}).items(): + await datasette.set_column_metadata( + dbname, tablename, columnname, "description", column_description + ) diff --git a/setup.py b/setup.py index e52b0b7..3573bc0 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup import os -VERSION = "0.1" +VERSION = "0.2" def get_long_description(): @@ -28,7 +28,7 @@ def get_long_description(): version=VERSION, packages=["datasette_remote_metadata"], entry_points={"datasette": ["remote_metadata = datasette_remote_metadata"]}, - install_requires=["datasette"], + install_requires=["datasette>=1.0a14"], extras_require={"test": ["pytest", "pytest-asyncio", "pytest-httpx"]}, tests_require=["datasette-remote-metadata[test]"], python_requires=">=3.6", diff --git a/tests/test_remote_metadata.py b/tests/test_remote_metadata.py index 7854e73..6ea3f0f 100644 --- a/tests/test_remote_metadata.py +++ b/tests/test_remote_metadata.py @@ -22,6 +22,7 @@ async def test_remote_metadata(httpx_mock): memory=True, metadata={"plugins": {"datasette-remote-metadata": {"url": TEST_URL}}}, ) + await datasette.invoke_startup() response = await datasette.client.get("/") assert response.status_code == 200 assert ">This is the remote metadata title<" in response.text