captapi 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- captapi/__init__.py +21 -0
- captapi/_generated.py +3164 -0
- captapi/_transport.py +99 -0
- captapi-0.1.0.dist-info/METADATA +0 -0
- captapi-0.1.0.dist-info/RECORD +6 -0
- captapi-0.1.0.dist-info/WHEEL +4 -0
captapi/_transport.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""HTTP transports for the generated Captapi SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
DEFAULT_BASE_URL = "https://api.captapi.com"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CaptapiError(Exception):
|
|
14
|
+
"""Raised for every failed request. Never fails silently."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, message: str, status_code: int = 0, code: str | None = None, detail: Any = None) -> None:
|
|
17
|
+
super().__init__(message)
|
|
18
|
+
self.status_code = status_code
|
|
19
|
+
self.code = code
|
|
20
|
+
self.detail = detail
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _resolve_key(api_key: str | None) -> str:
|
|
24
|
+
key = api_key or os.environ.get("CAPTAPI_API_KEY")
|
|
25
|
+
if not key:
|
|
26
|
+
raise CaptapiError(
|
|
27
|
+
"Missing API key. Pass api_key= or set CAPTAPI_API_KEY. "
|
|
28
|
+
"Get one at https://captapi.com/dashboard/api-keys",
|
|
29
|
+
status_code=401,
|
|
30
|
+
code="missing_api_key",
|
|
31
|
+
)
|
|
32
|
+
return key
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _clean_params(params: dict[str, Any]) -> dict[str, Any]:
|
|
36
|
+
return {k: v for k, v in params.items() if v is not None}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _check(response: httpx.Response, path: str) -> dict[str, Any]:
|
|
40
|
+
try:
|
|
41
|
+
body: Any = response.json()
|
|
42
|
+
except Exception:
|
|
43
|
+
body = None
|
|
44
|
+
|
|
45
|
+
ok = response.status_code < 400 and not (isinstance(body, dict) and body.get("success") is False)
|
|
46
|
+
if not ok:
|
|
47
|
+
detail = body.get("detail") or body.get("error") if isinstance(body, dict) else body
|
|
48
|
+
code = None
|
|
49
|
+
if isinstance(detail, dict) and detail.get("error"):
|
|
50
|
+
code = str(detail["error"])
|
|
51
|
+
elif isinstance(body, dict) and isinstance(body.get("error"), str):
|
|
52
|
+
code = body["error"]
|
|
53
|
+
raise CaptapiError(
|
|
54
|
+
f"Captapi {path} returned {response.status_code}: {detail!r}",
|
|
55
|
+
status_code=response.status_code,
|
|
56
|
+
code=code,
|
|
57
|
+
detail=detail,
|
|
58
|
+
)
|
|
59
|
+
if not isinstance(body, dict):
|
|
60
|
+
raise CaptapiError(f"Captapi {path} returned a non-JSON response", status_code=response.status_code)
|
|
61
|
+
return body
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class SyncTransport:
|
|
65
|
+
def __init__(self, api_key: str | None = None, base_url: str | None = None, timeout: float = 120.0) -> None:
|
|
66
|
+
self._client = httpx.Client(
|
|
67
|
+
base_url=(base_url or DEFAULT_BASE_URL).rstrip("/"),
|
|
68
|
+
headers={"authorization": f"Bearer {_resolve_key(api_key)}", "accept": "application/json"},
|
|
69
|
+
timeout=timeout,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def get(self, path: str, params: dict[str, Any]) -> dict[str, Any]:
|
|
73
|
+
try:
|
|
74
|
+
response = self._client.get(path, params=_clean_params(params))
|
|
75
|
+
except httpx.HTTPError as exc:
|
|
76
|
+
raise CaptapiError(f"Request to {path} failed: {exc}", code="network_error") from exc
|
|
77
|
+
return _check(response, path)
|
|
78
|
+
|
|
79
|
+
def close(self) -> None:
|
|
80
|
+
self._client.close()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class AsyncTransport:
|
|
84
|
+
def __init__(self, api_key: str | None = None, base_url: str | None = None, timeout: float = 120.0) -> None:
|
|
85
|
+
self._client = httpx.AsyncClient(
|
|
86
|
+
base_url=(base_url or DEFAULT_BASE_URL).rstrip("/"),
|
|
87
|
+
headers={"authorization": f"Bearer {_resolve_key(api_key)}", "accept": "application/json"},
|
|
88
|
+
timeout=timeout,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
async def get(self, path: str, params: dict[str, Any]) -> dict[str, Any]:
|
|
92
|
+
try:
|
|
93
|
+
response = await self._client.get(path, params=_clean_params(params))
|
|
94
|
+
except httpx.HTTPError as exc:
|
|
95
|
+
raise CaptapiError(f"Request to {path} failed: {exc}", code="network_error") from exc
|
|
96
|
+
return _check(response, path)
|
|
97
|
+
|
|
98
|
+
async def aclose(self) -> None:
|
|
99
|
+
await self._client.aclose()
|
|
Binary file
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
captapi/__init__.py,sha256=UVBOsOYW9gsjxn5rnjX5Sk_s_Ruhnv5WGDvDk3X4oX4,651
|
|
2
|
+
captapi/_generated.py,sha256=dPA8MDZBEyiuj_ju3aPbGaRVjeFmkdzSX1pgCmhfnwo,201758
|
|
3
|
+
captapi/_transport.py,sha256=7VMmJ3YqiDJXvbPrcvZpmM_JrhIe0eV1UAOv__LDFhU,3571
|
|
4
|
+
captapi-0.1.0.dist-info/METADATA,sha256=ZocKfyLHZnITUXB0Ofbf3i2EGu4CTcNpu6J-wxEqNHI,5299
|
|
5
|
+
captapi-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
6
|
+
captapi-0.1.0.dist-info/RECORD,,
|