Download backend/core/jsonutil.py from GerardCB/perch: direct link, hf CLI and curl.
- Browser
- Download file 1.47 kB
-
https://huggingface.co/spaces/GerardCB/perch/resolve/main/backend/core/jsonutil.py
- Command line
-
hf download hf://spaces/GerardCB/perch/backend/core/jsonutil.py
-
curl -L -o jsonutil.py https://huggingface.co/spaces/GerardCB/perch/resolve/main/backend/core/jsonutil.py
1.47 kB
| """ | |
| JSON that is actually valid JSON. | |
| Python's `json.dumps` accepts NaN and Infinity by default and emits them as bare | |
| `NaN` / `Infinity` tokens. Those are not valid JSON: the Gemini API rejects the | |
| payload with `400 INVALID_ARGUMENT ... Unexpected token`, and a browser's | |
| `JSON.parse` throws on them too. Because `dumps` does not raise, the problem | |
| slips through any "try dumps, fall back on error" guard. | |
| Non-finite values arrive naturally from analytics — AVG over an empty group, | |
| a ratio with a zero denominator, ST_Area on a degenerate geometry. They are | |
| converted to null, which is what "no value" means in JSON. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import math | |
| from typing import Any | |
| def json_safe(obj: Any) -> Any: | |
| """Recursively replace non-finite floats with None so the result is valid JSON.""" | |
| if isinstance(obj, float): | |
| return None if (math.isnan(obj) or math.isinf(obj)) else obj | |
| if isinstance(obj, dict): | |
| return {k: json_safe(v) for k, v in obj.items()} | |
| if isinstance(obj, (list, tuple)): | |
| return [json_safe(v) for v in obj] | |
| return obj | |
| def dumps_safe(obj: Any) -> str: | |
| """ | |
| Serialize to strictly-valid JSON. | |
| `allow_nan=False` makes a missed non-finite value raise instead of producing | |
| a payload that fails later at the API or in the browser; `default=str` | |
| handles dates and other stragglers. | |
| """ | |
| return json.dumps(json_safe(obj), allow_nan=False, default=str) | |