Made register_output_renderer callback optionally awaitable, closes #776

pull/783/head
Simon Willison 2020-05-27 19:43:30 -07:00
rodzic 52c4387c7d
commit 57f48b8416
4 zmienionych plików z 17 dodań i 6 usunięć

Wyświetl plik

@ -403,6 +403,8 @@ class DataView(BaseView):
args=request.args,
data=data,
)
if asyncio.iscoroutine(result):
result = await result
if result is None:
raise NotFound("No data")

Wyświetl plik

@ -736,7 +736,7 @@ register_output_renderer(datasette)
``datasette`` - :ref:`internals_datasette`
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
Allows the plugin to register a new output renderer, to output data in a custom format. The hook function should return a dictionary, or a list of dictionaries, which contain the file extension you want to handle and a callback function:
Registers a new output renderer, to output data in a custom format. The hook function should return a dictionary, or a list of dictionaries, of the following shape:
.. code-block:: python
@ -747,7 +747,11 @@ Allows the plugin to register a new output renderer, to output data in a custom
"render": render_test
}
This will register ``render_test`` to be called when paths with the extension ``.test`` (for example ``/database.test``, ``/database/table.test``, or ``/database/table/row.test``) are requested. When a request is received, the callback function is called with zero or more of the following arguments. Datasette will inspect your callback function and pass arguments that match its function signature.
This will register ``render_test`` to be called when paths with the extension ``.test`` (for example ``/database.test``, ``/database/table.test``, or ``/database/table/row.test``) are requested.
``render_test`` is a Python function. It can be a regular function or an ``async def render_test()`` awaitable function, depending on if it needs to make any asynchronous calls.
When a request is received, the callback function is called with zero or more of the following arguments. Datasette will inspect your callback function and pass arguments that match its function signature.
``datasette`` - :ref:`internals_datasette`
For accessing plugin configuration and executing queries.
@ -803,16 +807,18 @@ Here is a more complex example:
.. code-block:: python
def render_test(columns, rows):
async def render_test(datasette, columns, rows):
db = next(iter(datasette.databases.values()))
result = await db.execute("select sqlite_version()")
first_row = " | ".join(columns)
lines = [first_row]
lines.append("=" * len(first_row))
for row in rows:
lines.append(" | ".join(row))
return {
"body": "Hello World",
"body": "\n".join(lines),
"content_type": "text/plain; charset=utf-8",
"headers": {"x-pipes": "yay-pipes"}
"headers": {"x-sqlite-version": result.first()[0]},
}
Examples: `datasette-atom <https://github.com/simonw/datasette-atom>`_, `datasette-ics <https://github.com/simonw/datasette-ics>`_

Wyświetl plik

@ -2,13 +2,14 @@ from datasette import hookimpl
import json
def render_test_all_parameters(
async def render_test_all_parameters(
datasette, columns, rows, sql, query_name, database, table, request, view_name, data
):
headers = {}
for custom_header in request.args.getlist("header") or []:
key, value = custom_header.split(":")
headers[key] = value
result = await datasette.databases["fixtures"].execute("select 1 + 1")
return {
"body": json.dumps(
{
@ -21,6 +22,7 @@ def render_test_all_parameters(
"table": table,
"request": request,
"view_name": view_name,
"1+1": result.first()[0],
},
default=repr,
),

Wyświetl plik

@ -347,6 +347,7 @@ def test_register_output_renderer_all_parameters(app_client):
body = response.body.decode("utf-8")
body = at_memory_re.sub(" at 0xXXX", body)
assert {
"1+1": 2,
"datasette": "<datasette.app.Datasette object at 0xXXX>",
"columns": [
"pk",