Replace infinities in facet results with null in JSON output, closes #2954

This commit is contained in:
Tanbir 2026-09-23 17:22:33 +02:00
commit f63d647de0
2 changed files with 55 additions and 2 deletions

View file

@ -30,6 +30,10 @@ def convert_specific_columns_to_json(rows, columns, json_cols):
return new_rows
def _facet_without_infinites(facet):
return {**facet, "results": [remove_infinites(r) for r in facet["results"]]}
def json_renderer(request, args, data, error, truncated=None):
"""Render a response as JSON"""
status_code = 200
@ -44,8 +48,23 @@ def json_renderer(request, args, data, error, truncated=None):
)
# unless _json_infinity=1 requested, replace infinity with None
if "rows" in data and not value_as_boolean(args.get("_json_infinity", "0")):
data["rows"] = [remove_infinites(row) for row in data["rows"]]
if not value_as_boolean(args.get("_json_infinity", "0")):
if "rows" in data:
data["rows"] = [remove_infinites(row) for row in data["rows"]]
# Facet values and labels can be infinities too
if isinstance(data.get("facet_results"), dict):
data["facet_results"] = {
**data["facet_results"],
"results": {
name: _facet_without_infinites(facet)
for name, facet in data["facet_results"]["results"].items()
},
}
if isinstance(data.get("sorted_facet_results"), list):
data["sorted_facet_results"] = [
_facet_without_infinites(facet)
for facet in data["sorted_facet_results"]
]
# Deal with the _shape option
shape = args.get("_shape", "objects")

View file

@ -1290,6 +1290,40 @@ async def test_infinity_returned_as_null(ds_client):
]
@pytest.mark.asyncio
@pytest.mark.parametrize("extra", ("facet_results", "sorted_facet_results"))
async def test_infinity_facet_values_returned_as_null(ds_client, extra):
# https://github.com/simonw/datasette/issues/2954
response = await ds_client.get(
"/fixtures/infinity.json?_facet=value&_extra=" + extra
)
assert response.status_code == 200
def reject_constant(token):
raise ValueError(f"Non-JSON numeric literal: {token}")
data = json.loads(response.text, parse_constant=reject_constant)
facets = data[extra]
facet = facets["results"]["value"] if extra == "facet_results" else facets[0]
values = sorted(
((r["value"], r["label"]) for r in facet["results"]),
key=lambda pair: (pair[0] is not None, pair),
)
assert values == [(None, None), (None, None), (1.5, 1.5)]
@pytest.mark.asyncio
async def test_infinity_facet_values_returned_as_invalid_json_if_requested(ds_client):
response = await ds_client.get(
"/fixtures/infinity.json?_facet=value&_extra=facet_results&_json_infinity=1"
)
values = {
r["value"]
for r in response.json()["facet_results"]["results"]["value"]["results"]
}
assert values == {float("inf"), float("-inf"), 1.5}
@pytest.mark.asyncio
async def test_infinity_returned_as_invalid_json_if_requested(ds_client):
response = await ds_client.get(