fetch_json with timeout and error mapping

Python
"""Fetch JSON over HTTP with an explicit timeout and readable failures."""
import json
import urllib.error
import urllib.request
from typing import Any


def fetch_json(
    url: str, *, timeout: float = 10.0, headers: dict[str, str] | None = None
) -> Any:
    """GET url and decode the body; raise RuntimeError on any failure."""
    merged = {"Accept": "application/json", "User-Agent": "bits-fetch/1.0"}
    merged.update(headers or {})
    request = urllib.request.Request(url, headers=merged)
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:
            charset = response.headers.get_content_charset() or "utf-8"
            body = response.read().decode(charset)
    except urllib.error.HTTPError as exc:
        raise RuntimeError(f"HTTP {exc.code} for {url}: {exc.reason}") from exc
    except urllib.error.URLError as exc:
        raise RuntimeError(f"cannot reach {url}: {exc.reason}") from exc
    except TimeoutError as exc:
        raise RuntimeError(f"timed out after {timeout}s: {url}") from exc
    try:
        return json.loads(body)
    except json.JSONDecodeError as exc:
        raise RuntimeError(f"bad JSON from {url}: {exc.msg} at line {exc.lineno}") from exc