diff --git a/datasette/views/base.py b/datasette/views/base.py index 5a5fe056..d56fd2f6 100644 --- a/datasette/views/base.py +++ b/datasette/views/base.py @@ -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") diff --git a/docs/plugins.rst b/docs/plugins.rst index 27f00476..ebf6adf6 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -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 `_, `datasette-ics `_ diff --git a/tests/plugins/register_output_renderer.py b/tests/plugins/register_output_renderer.py index 2ea5660e..d4c1228d 100644 --- a/tests/plugins/register_output_renderer.py +++ b/tests/plugins/register_output_renderer.py @@ -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, ), diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 0e4186d5..94b69c1f 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -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": "", "columns": [ "pk",