From 9cdf95ac2c47fe80bc368e2564f5554de1dc998a Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 16 Sep 2026 21:23:54 -0700 Subject: [PATCH] Show correct query timings, closes #2446 --- datasette/views/table.py | 5 ++++- tests/test_table_html.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/datasette/views/table.py b/datasette/views/table.py index 22dca7e0..26ce2acd 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -1,6 +1,7 @@ import asyncio import itertools import json +import time import urllib import urllib.parse from dataclasses import dataclass, field @@ -1801,6 +1802,7 @@ async def table_view_traced(datasette, request): context_for_html_hack = True default_labels = True + start = time.perf_counter() view_data = await table_view_data( datasette, request, @@ -1811,6 +1813,7 @@ async def table_view_traced(datasette, request): ) if isinstance(view_data, Response): return view_data + query_ms = (time.perf_counter() - start) * 1000 data, rows, columns, _expanded_columns, sql, next_url = view_data # Handle formats from plugins @@ -1957,7 +1960,7 @@ async def table_view_traced(datasette, request): resource=DatabaseResource(database=resolved.db.name), actor=request.actor, ), - query_ms=1.2, + query_ms=query_ms, select_templates=[ f"{'*' if template_name == template.name else ''}{template_name}" for template_name in templates diff --git a/tests/test_table_html.py b/tests/test_table_html.py index 0bdc7282..c72aaf9b 100644 --- a/tests/test_table_html.py +++ b/tests/test_table_html.py @@ -1,5 +1,6 @@ import pathlib import urllib.parse +from types import SimpleNamespace import pytest from bs4 import BeautifulSoup as Soup @@ -72,6 +73,21 @@ DEFAULT_EXPRESSION_OPTIONS = [ ] +@pytest.mark.asyncio +@pytest.mark.parametrize("table", ("simple_primary_key", "simple_view")) +@pytest.mark.parametrize("duration", (0.125, 0.25)) +async def test_table_footer_query_ms(ds_client, monkeypatch, table, duration): + times = iter((10.0, 10.0 + duration)) + # Only mock the table view's clock, leaving SQL time limits unaffected. + monkeypatch.setattr( + "datasette.views.table.time", SimpleNamespace(perf_counter=lambda: next(times)) + ) + response = await ds_client.get(f"/fixtures/{table}") + assert response.status_code == 200 + footer = Soup(response.text, "html.parser").find("footer") + assert f"Queries took {duration * 1000}ms" in footer.get_text() + + @pytest.mark.asyncio @pytest.mark.parametrize( "path,expected_definition_sql",