wexa-sdk 0.1.0__py3-none-any.whl → 0.1.1__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.

Potentially problematic release.


This version of wexa-sdk might be problematic. Click here for more details.

@@ -0,0 +1 @@
1
+ from .http import HttpClient, ApiError
wexa_sdk/core/http.py ADDED
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+ import json
3
+ import time
4
+ from typing import Any, Dict, Optional
5
+
6
+ import httpx
7
+
8
+ RETRY_STATUS = {429, 500, 502, 503, 504}
9
+
10
+ class ApiError(Exception):
11
+ def __init__(self, status: int, detail: Optional[str] = None, code: Optional[str] = None, request_id: Optional[str] = None, raw: Any = None):
12
+ super().__init__(detail or f"API Error {status}")
13
+ self.status = status
14
+ self.code = code
15
+ self.detail = detail
16
+ self.request_id = request_id
17
+ self.raw = raw
18
+
19
+ class HttpClient:
20
+ def __init__(self, base_url: str, api_key: str, user_agent: Optional[str] = None, timeout: Optional[dict] = None, retries: Optional[dict] = None):
21
+ self.base_url = base_url.rstrip("/")
22
+ self.api_key = api_key
23
+ self.user_agent = user_agent
24
+ self.timeout = {
25
+ "connectTimeoutMs": (timeout or {}).get("connectTimeoutMs", 5000),
26
+ "readTimeoutMs": (timeout or {}).get("readTimeoutMs", 30000),
27
+ }
28
+ self.retries = {
29
+ "attempts": (retries or {}).get("attempts", 3),
30
+ "baseDelayMs": (retries or {}).get("baseDelayMs", 500),
31
+ "maxDelayMs": (retries or {}).get("maxDelayMs", 30000),
32
+ }
33
+ self._client = httpx.Client(timeout=self.timeout["readTimeoutMs"] / 1000)
34
+
35
+ def request(self, method: str, path: str, *, params: Optional[Dict[str, Any]] = None, json: Any = None, headers: Optional[Dict[str, str]] = None):
36
+ url = f"{self.base_url}{path}"
37
+ hdrs = {
38
+ "content-type": "application/json",
39
+ "x-api-key": self.api_key,
40
+ "X-Wexa-SDK-Version": "py/0.1.0",
41
+ }
42
+ if self.user_agent:
43
+ hdrs["User-Agent"] = self.user_agent
44
+ if headers:
45
+ hdrs.update(headers)
46
+
47
+ req_id = headers.get("x-client-request-id") if headers else None
48
+ if not req_id:
49
+ req_id = str(int(time.time() * 1000))
50
+ hdrs["x-client-request-id"] = req_id
51
+
52
+ attempt = 0
53
+ last_err: Optional[Exception] = None
54
+ while attempt < self.retries["attempts"]:
55
+ try:
56
+ resp = self._client.request(method, url, params=params, json=json, headers=hdrs)
57
+ res_req_id = resp.headers.get("x-request-id") or req_id
58
+ text = resp.text
59
+ try:
60
+ data = resp.json() if text else None
61
+ except Exception:
62
+ data = text
63
+ if not resp.is_success:
64
+ detail = (isinstance(data, dict) and (data.get("detail") or data.get("error") or data.get("message"))) or text or f"HTTP {resp.status_code}"
65
+ if resp.status_code in RETRY_STATUS and attempt < self.retries["attempts"] - 1:
66
+ time.sleep(self._backoff(attempt) / 1000)
67
+ attempt += 1
68
+ continue
69
+ raise ApiError(status=resp.status_code, detail=detail, request_id=res_req_id, raw=data)
70
+ return data
71
+ except ApiError:
72
+ raise
73
+ except Exception as e: # network error
74
+ last_err = e
75
+ if attempt < self.retries["attempts"] - 1:
76
+ time.sleep(self._backoff(attempt) / 1000)
77
+ attempt += 1
78
+ continue
79
+ raise ApiError(status=0, detail=str(e), request_id=req_id, raw=e)
80
+ raise last_err # type: ignore
81
+
82
+ def _backoff(self, attempt: int) -> int:
83
+ import random
84
+ jitter = random.random() * 0.2 + 0.9
85
+ delay = min(self.retries["maxDelayMs"], int(self.retries["baseDelayMs"] * (2 ** attempt)))
86
+ return int(delay * jitter)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wexa-sdk
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Official Wexa Python SDK
5
5
  Author: Wexa
6
6
  License: Apache-2.0
@@ -15,8 +15,10 @@ wexa_sdk/tasks.py,sha256=YRXMxQwgpiflAxyUqedyo4LB6bsO7zsiM5uP0uE8_Ds,1349
15
15
  wexa_sdk/connectors/__init__.py,sha256=eEtSQ8oXlYnoD3CUxPCF3Il6bgGyN6zfKI3_Pu41jXo,51
16
16
  wexa_sdk/connectors/core.py,sha256=4dFp0CVCysUsIOT7l9V7bzXu1jRx9EBGZv2_bQkKPsQ,1188
17
17
  wexa_sdk/connectors/google_drive.py,sha256=Dibfoy8uKcGygmjCnrolPhKq5Fy5ye5-ee_kI4XD7kY,945
18
+ wexa_sdk/core/__init__.py,sha256=K-bUeDdR3iblN9BNwMQ-ZMbOcAJSAUkNwuoVz5L3fC4,39
19
+ wexa_sdk/core/http.py,sha256=4O59C5VlVhxaQNkjJ0UpARZk3g-rEoOxEbwE0u9NWbY,3721
18
20
  wexa_sdk/models/__init__.py,sha256=yxQUjah8RTJh531y8QQXEeh5dp0d5k55dsrVvR4O1N8,75
19
- wexa_sdk-0.1.0.dist-info/METADATA,sha256=WZEHzNIIMLoIwp6B7E1ctiOf9V9nekaiDclogl4DsQg,581
20
- wexa_sdk-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
- wexa_sdk-0.1.0.dist-info/top_level.txt,sha256=iXL6c0Kro-mkIoNbjT76txRuoilWB-P7AHhmvKtdXkA,9
22
- wexa_sdk-0.1.0.dist-info/RECORD,,
21
+ wexa_sdk-0.1.1.dist-info/METADATA,sha256=aSGcd5eAF85HBhI-kyTaSSNQm_-sJ66IuLfm5osjShw,581
22
+ wexa_sdk-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ wexa_sdk-0.1.1.dist-info/top_level.txt,sha256=iXL6c0Kro-mkIoNbjT76txRuoilWB-P7AHhmvKtdXkA,9
24
+ wexa_sdk-0.1.1.dist-info/RECORD,,