Files
egutierrez 5a324f6554 feat: funciones Python infra y tipos Python (core, datascience, infra)
Infra: cache_to_file, cache_to_sqlite, http_download_file, http_get_json,
http_post_json, read_file_with_encoding, safe_extract_zip, scan_directory,
setup_logger, normalize_zip_filenames.
Tipos: 30+ tipos core (agent_action, context, task, message, parse_result...),
6 tipos datascience (entity_candidate, extraction_result...), 2 tipos infra.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:11:43 +02:00

59 lines
1.9 KiB
Python

"""POST request JSON — HTTP client sin dependencias externas."""
import json
import urllib.error
import urllib.request
def http_post_json(
url: str,
body: dict,
headers: dict[str, str] | None = None,
timeout: float = 30.0,
) -> dict:
"""Realiza un POST request con body JSON y parsea la respuesta como JSON.
Agrega automaticamente ``Content-Type: application/json`` y
``Accept: application/json``. Si el status es >= 400 lanza RuntimeError
con status code, url y los primeros 200 caracteres del body.
Args:
url: URL del endpoint.
body: Datos a serializar como JSON en el cuerpo del request.
headers: Headers HTTP adicionales. Se fusionan con los defaults.
timeout: Segundos maximo de espera (default 30).
Returns:
Respuesta parseada como dict o list.
Raises:
RuntimeError: Si status >= 400 o si el body de respuesta no es JSON valido.
"""
all_headers: dict[str, str] = {
"Content-Type": "application/json",
"Accept": "application/json",
}
if headers:
all_headers.update(headers)
data = json.dumps(body, ensure_ascii=False).encode("utf-8")
req = urllib.request.Request(url, data=data, headers=all_headers, method="POST")
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
raw = resp.read()
except urllib.error.HTTPError as e:
body_preview = e.read(200).decode("utf-8", errors="replace")
short_url = url[:100] if len(url) > 100 else url
raise RuntimeError(
f"http_post_json: HTTP {e.code} at {short_url!r}{body_preview}"
) from e
try:
return json.loads(raw)
except json.JSONDecodeError as e:
preview = raw[:200].decode("utf-8", errors="replace")
raise RuntimeError(
f"http_post_json: response is not valid JSON — {preview}"
) from e