Use Jinja async mode, refs #628

This commit is contained in:
Simon Willison 2019-11-13 17:20:31 -08:00
commit 7eb2be41df
5 changed files with 31 additions and 4 deletions

View file

@ -583,7 +583,9 @@ class Datasette:
),
]
)
self.jinja_env = Environment(loader=template_loader, autoescape=True)
self.jinja_env = Environment(
loader=template_loader, autoescape=True, enable_async=True
)
self.jinja_env.filters["escape_css_string"] = escape_css_string
self.jinja_env.filters["quote_plus"] = lambda u: urllib.parse.quote_plus(u)
self.jinja_env.filters["escape_sqlite"] = escape_sqlite
@ -730,5 +732,5 @@ class DatasetteRouter(AsgiRouter):
else:
template = self.ds.jinja_env.select_template(templates)
await asgi_send_html(
send, template.render(info), status=status, headers=headers
send, await template.render_async(info), status=status, headers=headers
)

View file

@ -139,7 +139,7 @@ class BaseView(AsgiView):
extra_template_vars.update(extra_vars)
return Response.html(
template.render(
await template.render_async(
{
**context,
**{

View file

@ -446,13 +446,19 @@ def render_cell(value, database):
@hookimpl
def extra_template_vars(template, database, table, view_name, request, datasette):
async def query_database(sql):
first_db = list(datasette.databases.keys())[0]
return (
await datasette.execute(first_db, sql)
).rows[0][0]
async def inner():
return {
"extra_template_vars_from_awaitable": json.dumps({
"template": template,
"scope_path": request.scope["path"],
"awaitable": True,
}, default=lambda b: b.decode("utf8"))
}, default=lambda b: b.decode("utf8")),
"query_database": query_database,
}
return inner

View file

@ -1,5 +1,6 @@
from bs4 import BeautifulSoup as Soup
from .fixtures import app_client, make_app_client, TEMP_PLUGIN_SECRET_FILE # noqa
from datasette.utils import sqlite3
import base64
import json
import os
@ -214,3 +215,20 @@ def test_plugins_extra_template_vars(restore_working_directory):
"awaitable": True,
"scope_path": "/-/metadata",
} == extra_template_vars_from_awaitable
def test_plugins_async_template_function(restore_working_directory):
for client in make_app_client(
template_dir=str(pathlib.Path(__file__).parent / "test_templates")
):
response = client.get("/-/metadata")
assert response.status == 200
extra_from_awaitable_function = (
Soup(response.body, "html.parser")
.select("pre.extra_from_awaitable_function")[0]
.text
)
expected = (
sqlite3.connect(":memory:").execute("select sqlite_version()").fetchone()[0]
)
assert expected == extra_from_awaitable_function

View file

@ -5,4 +5,5 @@
Test data for extra_template_vars:
<pre class="extra_template_vars">{{ extra_template_vars|safe }}</pre>
<pre class="extra_template_vars_from_awaitable">{{ extra_template_vars_from_awaitable|safe }}</pre>
<pre class="extra_from_awaitable_function">{{ query_database("select sqlite_version();") }}</pre>
{% endblock %}