Files
GUI-Agent/SystemTest-Agent/app/http_client.py
T

61 lines
1.9 KiB
Python

from __future__ import annotations
import json
from dataclasses import dataclass
from typing import Any
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
@dataclass
class HttpClientError(RuntimeError):
status: int
message: str
payload: dict[str, Any] | None = None
def __str__(self) -> str:
return f"HTTP {self.status}: {self.message}"
def _network_error_message(exc: BaseException, timeout: float) -> str:
reason = getattr(exc, "reason", exc)
if isinstance(exc, TimeoutError) or isinstance(reason, TimeoutError):
return f"timed out after {timeout:g}s"
return str(reason) or type(reason).__name__
def request_json(
method: str,
url: str,
payload: dict[str, Any] | None = None,
token: str | None = None,
timeout: float = 5.0,
) -> dict[str, Any]:
body = None
headers = {"Accept": "application/json"}
if payload is not None:
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
headers["Content-Type"] = "application/json; charset=utf-8"
if token:
headers["Authorization"] = f"Bearer {token}"
request = Request(url, data=body, headers=headers, method=method.upper())
try:
with urlopen(request, timeout=timeout) as response:
response_body = response.read()
if not response_body:
return {}
return json.loads(response_body.decode("utf-8"))
except HTTPError as exc:
raw = exc.read().decode("utf-8", errors="replace")
payload_obj = None
message = raw or exc.reason
try:
payload_obj = json.loads(raw)
message = payload_obj.get("error") or message
except json.JSONDecodeError:
pass
raise HttpClientError(exc.code, message, payload_obj) from exc
except (URLError, TimeoutError, OSError) as exc:
raise HttpClientError(0, _network_error_message(exc, timeout), None) from exc