from __future__ import annotations import json from typing import Any, Optional import httpx from .config import Config class GPFSError(RuntimeError): def __init__(self, status: int, body: Any, method: str, url: str) -> None: super().__init__(f"{method} {url} -> HTTP {status}") self.status = status self.body = body self.method = method self.url = url class GPFSClient: def __init__(self, cfg: Config) -> None: self._cfg = cfg self._client = httpx.Client( base_url=cfg.gpfs_base, auth=(cfg.gpfs_username, cfg.gpfs_password), verify=cfg.verify_tls, timeout=cfg.timeout, headers={ "Accept": "application/json", "Content-Type": "application/json", }, ) def close(self) -> None: self._client.close() def __enter__(self) -> "GPFSClient": return self def __exit__(self, *_: object) -> None: self.close() def request( self, method: str, path: str, params: Optional[dict[str, Any]] = None, body: Optional[dict[str, Any]] = None, ) -> dict[str, Any]: if not path.startswith("/"): path = "/" + path response = self._client.request( method=method.upper(), url=path, params=params or None, content=json.dumps(body) if body is not None else None, ) text = response.text data: Any try: data = response.json() if text else None except json.JSONDecodeError: data = None return { "status": response.status_code, "ok": response.is_success, "url": str(response.request.url), "method": method.upper(), "data": data, "text": None if data is not None else text, }