kopia lustrzana https://github.com/simonw/datasette
Added asgi_wrapper plugin hook, closes #520
rodzic
b9ede4c189
commit
93bfa26bfd
|
@ -651,9 +651,12 @@ class Datasette:
|
|||
if not database.is_mutable:
|
||||
await database.table_counts(limit=60 * 60 * 1000)
|
||||
|
||||
return AsgiLifespan(
|
||||
asgi = AsgiLifespan(
|
||||
AsgiTracer(DatasetteRouter(self, routes)), on_startup=setup_db
|
||||
)
|
||||
for wrapper in pm.hook.asgi_wrapper(datasette=self):
|
||||
asgi = wrapper(asgi)
|
||||
return asgi
|
||||
|
||||
|
||||
class DatasetteRouter(AsgiRouter):
|
||||
|
|
|
@ -5,6 +5,11 @@ hookspec = HookspecMarker("datasette")
|
|||
hookimpl = HookimplMarker("datasette")
|
||||
|
||||
|
||||
@hookspec
|
||||
def asgi_wrapper(datasette):
|
||||
"Returns an ASGI middleware callable to wrap our ASGI application with"
|
||||
|
||||
|
||||
@hookspec
|
||||
def prepare_connection(conn):
|
||||
"Modify SQLite connection in some way e.g. register custom SQL functions"
|
||||
|
|
|
@ -666,3 +666,44 @@ The plugin hook can then be used to register the new facet class like this:
|
|||
@hookimpl
|
||||
def register_facet_classes():
|
||||
return [SpecialFacet]
|
||||
|
||||
|
||||
.. _plugin_asgi_wrapper:
|
||||
|
||||
asgi_wrapper(datasette)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Return an `ASGI <https://asgi.readthedocs.io/>`__ middleware wrapper function that will be applied to the Datasette ASGI application.
|
||||
|
||||
This is a very powerful hook. You can use it to manipulate the entire Datasette response, or even to configure new URL routes that will be handled by your own custom code.
|
||||
|
||||
You can write your ASGI code directly against the low-level specification, or you can use the middleware utilites provided by an ASGI framework such as `Starlette <https://www.starlette.io/middleware/>`__.
|
||||
|
||||
This example plugin adds a ``x-databases`` HTTP header listing the currently attached databases:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from datasette import hookimpl
|
||||
from functools import wraps
|
||||
|
||||
|
||||
@hookimpl
|
||||
def asgi_wrapper(datasette):
|
||||
def wrap_with_databases_header(app):
|
||||
@wraps(app)
|
||||
async def add_x_databases_header(scope, recieve, send):
|
||||
async def wrapped_send(event):
|
||||
if event["type"] == "http.response.start":
|
||||
original_headers = event.get("headers") or []
|
||||
event = {
|
||||
"type": event["type"],
|
||||
"status": event["status"],
|
||||
"headers": original_headers + [
|
||||
[b"x-databases",
|
||||
", ".join(datasette.databases.keys()).encode("utf-8")]
|
||||
],
|
||||
}
|
||||
await send(event)
|
||||
await app(scope, recieve, wrapped_send)
|
||||
return add_x_databases_header
|
||||
return wrap_with_databases_header
|
||||
|
|
|
@ -372,6 +372,7 @@ def render_cell(value, column, table, database, datasette):
|
|||
|
||||
PLUGIN2 = """
|
||||
from datasette import hookimpl
|
||||
from functools import wraps
|
||||
import jinja2
|
||||
import json
|
||||
|
||||
|
@ -413,6 +414,28 @@ def render_cell(value, database):
|
|||
label=jinja2.escape(data["label"] or "") or " "
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@hookimpl
|
||||
def asgi_wrapper(datasette):
|
||||
def wrap_with_databases_header(app):
|
||||
@wraps(app)
|
||||
async def add_x_databases_header(scope, recieve, send):
|
||||
async def wrapped_send(event):
|
||||
if event["type"] == "http.response.start":
|
||||
original_headers = event.get("headers") or []
|
||||
event = {
|
||||
"type": event["type"],
|
||||
"status": event["status"],
|
||||
"headers": original_headers + [
|
||||
[b"x-databases",
|
||||
", ".join(datasette.databases.keys()).encode("utf-8")]
|
||||
],
|
||||
}
|
||||
await send(event)
|
||||
await app(scope, recieve, wrapped_send)
|
||||
return add_x_databases_header
|
||||
return wrap_with_databases_header
|
||||
"""
|
||||
|
||||
TABLES = (
|
||||
|
|
|
@ -162,3 +162,8 @@ def test_plugins_extra_body_script(app_client, path, expected_extra_body_script)
|
|||
json_data = r.search(app_client.get(path).body.decode("utf8")).group(1)
|
||||
actual_data = json.loads(json_data)
|
||||
assert expected_extra_body_script == actual_data
|
||||
|
||||
|
||||
def test_plugins_asgi_wrapper(app_client):
|
||||
response = app_client.get("/fixtures")
|
||||
assert "fixtures" == response.headers["x-databases"]
|
||||
|
|
Ładowanie…
Reference in New Issue