diff --git a/datasette/app.py b/datasette/app.py index 941794f9..0437a75b 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -3,6 +3,7 @@ import asgi_csrf import collections import datetime import hashlib +import inspect import itertools import json import os @@ -40,6 +41,7 @@ from .database import Database, QueryInterrupted from .utils import ( async_call_with_supported_arguments, + call_with_supported_arguments, escape_css_string, escape_sqlite, format_bytes, @@ -1056,14 +1058,24 @@ def _cleaner_task_str(task): def wrap_view(view_fn, datasette): async def asgi_view_fn(scope, receive, send): - response = await async_call_with_supported_arguments( - view_fn, - scope=scope, - receive=receive, - send=send, - request=Request(scope, receive), - datasette=datasette, - ) + if inspect.iscoroutinefunction(view_fn): + response = await async_call_with_supported_arguments( + view_fn, + scope=scope, + receive=receive, + send=send, + request=Request(scope, receive), + datasette=datasette, + ) + else: + response = call_with_supported_arguments( + view_fn, + scope=scope, + receive=receive, + send=send, + request=Request(scope, receive), + datasette=datasette, + ) if response is not None: await response.asgi_send(send) diff --git a/docs/plugin_hooks.rst b/docs/plugin_hooks.rst index 2de0cccc..4e118bdf 100644 --- a/docs/plugin_hooks.rst +++ b/docs/plugin_hooks.rst @@ -514,7 +514,7 @@ register_routes() Register additional view functions to execute for specified URL routes. -Return a list of ``(regex, async_view_function)`` pairs, something like this: +Return a list of ``(regex, view_function)`` pairs, something like this: .. code-block:: python @@ -554,6 +554,8 @@ The optional view function arguments are as follows: ``receive`` - function The ASGI receive function. +The view function can be a regular function or an ``async def`` function, depending on if it needs to use any ``await`` APIs. + The function can either return a :ref:`internals_response` or it can return nothing and instead respond directly to the request using the ASGI ``send`` function (for advanced uses only). Examples: `datasette-auth-github `__, `datasette-psutil `__ diff --git a/tests/plugins/my_plugin.py b/tests/plugins/my_plugin.py index 35d7eb54..45eae412 100644 --- a/tests/plugins/my_plugin.py +++ b/tests/plugins/my_plugin.py @@ -187,12 +187,16 @@ def register_routes(): await datasette.render_template("csrftoken_form.html", request=request) ) + def not_async(): + return Response.html("This was not async") + return [ (r"/one/$", one), (r"/two/(?P.*)$", two), (r"/three/$", three), (r"/post/$", post), (r"/csrftoken-form/$", csrftoken_form), + (r"/not-async/$", not_async), ] diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 1a6f004a..a7736756 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -565,7 +565,12 @@ def test_actor_json(app_client): @pytest.mark.parametrize( - "path,body", [("/one/", "2"), ("/two/Ray?greeting=Hail", "Hail Ray"),] + "path,body", + [ + ("/one/", "2"), + ("/two/Ray?greeting=Hail", "Hail Ray"), + ("/not-async/", "This was not async"), + ], ) def test_register_routes(app_client, path, body): response = app_client.get(path)