kainguru-sdk 0.1.8.dev0__tar.gz → 0.2.9.dev0__tar.gz
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.
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/PKG-INFO +10 -2
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/README.md +8 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/pyproject.toml +1 -1
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_config.py +3 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_transport.py +66 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/async_client.py +5 -1
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/client.py +5 -1
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/.gitignore +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/MAINTAINERS.md +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/Makefile +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/__init__.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_errors.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_polling.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/models.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/py.typed +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/__init__.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/_common.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/executions.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/finetuning.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/conftest.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/resources/openapi.json +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/test_auth.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/test_executions.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/test_finetuning.py +0 -0
- {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/test_polling.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: kainguru-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.9.dev0
|
|
4
4
|
Summary: Python SDK for the Kainguru ML platform — run models and fine-tune them.
|
|
5
5
|
Project-URL: Homepage, https://kainguru.com
|
|
6
6
|
Project-URL: Repository, https://github.com/kainguru/kainguru
|
|
@@ -191,6 +191,7 @@ client = KainguruClient(
|
|
|
191
191
|
base_url="https://your-host/api", # required, full host incl. /api context path
|
|
192
192
|
timeout=30.0, # per-request timeout in s
|
|
193
193
|
max_retries=3, # retries on 429 / 5xx / network
|
|
194
|
+
debug=True, # verbose request/response logging (default False)
|
|
194
195
|
)
|
|
195
196
|
```
|
|
196
197
|
|
|
@@ -200,6 +201,13 @@ the dashboard's `/api` context path.
|
|
|
200
201
|
|
|
201
202
|
Every method also accepts a per-request `api_key=` to override the client key for one call.
|
|
202
203
|
|
|
204
|
+
### Debug logging
|
|
205
|
+
|
|
206
|
+
Pass `debug=True` to trace every request and response on the `kainguru` logger (the
|
|
207
|
+
`X-API-Key` header is redacted). If your app hasn't configured that logger, the SDK
|
|
208
|
+
attaches a stderr handler at `DEBUG` level so the traces are visible out of the box.
|
|
209
|
+
Keep it off in production — request and response bodies are logged in full.
|
|
210
|
+
|
|
203
211
|
---
|
|
204
212
|
|
|
205
213
|
## Error handling
|
|
@@ -162,6 +162,7 @@ client = KainguruClient(
|
|
|
162
162
|
base_url="https://your-host/api", # required, full host incl. /api context path
|
|
163
163
|
timeout=30.0, # per-request timeout in s
|
|
164
164
|
max_retries=3, # retries on 429 / 5xx / network
|
|
165
|
+
debug=True, # verbose request/response logging (default False)
|
|
165
166
|
)
|
|
166
167
|
```
|
|
167
168
|
|
|
@@ -171,6 +172,13 @@ the dashboard's `/api` context path.
|
|
|
171
172
|
|
|
172
173
|
Every method also accepts a per-request `api_key=` to override the client key for one call.
|
|
173
174
|
|
|
175
|
+
### Debug logging
|
|
176
|
+
|
|
177
|
+
Pass `debug=True` to trace every request and response on the `kainguru` logger (the
|
|
178
|
+
`X-API-Key` header is redacted). If your app hasn't configured that logger, the SDK
|
|
179
|
+
attaches a stderr handler at `DEBUG` level so the traces are visible out of the box.
|
|
180
|
+
Keep it off in production — request and response bodies are logged in full.
|
|
181
|
+
|
|
174
182
|
---
|
|
175
183
|
|
|
176
184
|
## Error handling
|
|
@@ -18,6 +18,7 @@ class KainguruConfig:
|
|
|
18
18
|
timeout: float
|
|
19
19
|
max_retries: int
|
|
20
20
|
retry_base_delay: float
|
|
21
|
+
debug: bool = False
|
|
21
22
|
|
|
22
23
|
@classmethod
|
|
23
24
|
def resolve(
|
|
@@ -28,6 +29,7 @@ class KainguruConfig:
|
|
|
28
29
|
timeout: float = DEFAULT_TIMEOUT,
|
|
29
30
|
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
30
31
|
retry_base_delay: float = DEFAULT_RETRY_BASE_DELAY,
|
|
32
|
+
debug: bool = False,
|
|
31
33
|
) -> KainguruConfig:
|
|
32
34
|
"""Resolve configuration, failing fast when the caller omits a required field.
|
|
33
35
|
|
|
@@ -56,6 +58,7 @@ class KainguruConfig:
|
|
|
56
58
|
timeout=timeout,
|
|
57
59
|
max_retries=max_retries,
|
|
58
60
|
retry_base_delay=retry_base_delay,
|
|
61
|
+
debug=debug,
|
|
59
62
|
)
|
|
60
63
|
|
|
61
64
|
|
|
@@ -8,6 +8,7 @@ identically.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import asyncio
|
|
11
|
+
import logging
|
|
11
12
|
import random
|
|
12
13
|
import time
|
|
13
14
|
from typing import Any, TypeVar
|
|
@@ -28,6 +29,67 @@ API_KEY_HEADER = "X-API-Key"
|
|
|
28
29
|
|
|
29
30
|
ModelT = TypeVar("ModelT", bound=BaseModel)
|
|
30
31
|
|
|
32
|
+
#: Logger used for verbose request/response tracing when the client is in debug mode.
|
|
33
|
+
logger = logging.getLogger("kainguru")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def enable_debug_logging() -> None:
|
|
37
|
+
"""Make the ``kainguru`` logger emit DEBUG traces to stderr.
|
|
38
|
+
|
|
39
|
+
Called by the clients when ``debug=True``. If the application has already
|
|
40
|
+
configured handlers for the ``kainguru`` logger, those are left untouched and
|
|
41
|
+
only the level is lowered.
|
|
42
|
+
"""
|
|
43
|
+
logger.setLevel(logging.DEBUG)
|
|
44
|
+
if not logger.handlers:
|
|
45
|
+
handler = logging.StreamHandler()
|
|
46
|
+
handler.setFormatter(
|
|
47
|
+
logging.Formatter("%(asctime)s [kainguru] %(levelname)s %(message)s")
|
|
48
|
+
)
|
|
49
|
+
logger.addHandler(handler)
|
|
50
|
+
logger.propagate = False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _redact_headers(headers: dict[str, str]) -> dict[str, str]:
|
|
54
|
+
safe = dict(headers)
|
|
55
|
+
if API_KEY_HEADER in safe:
|
|
56
|
+
safe[API_KEY_HEADER] = "***redacted***"
|
|
57
|
+
return safe
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _log_request(
|
|
61
|
+
config: KainguruConfig,
|
|
62
|
+
method: str,
|
|
63
|
+
url: str,
|
|
64
|
+
headers: dict[str, str],
|
|
65
|
+
params: dict[str, Any] | None,
|
|
66
|
+
json: dict[str, Any] | None,
|
|
67
|
+
attempt: int,
|
|
68
|
+
) -> None:
|
|
69
|
+
if not config.debug:
|
|
70
|
+
return
|
|
71
|
+
logger.debug(
|
|
72
|
+
"--> %s %s (attempt %d) params=%s headers=%s json=%s",
|
|
73
|
+
method,
|
|
74
|
+
url,
|
|
75
|
+
attempt + 1,
|
|
76
|
+
params,
|
|
77
|
+
_redact_headers(headers),
|
|
78
|
+
json,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _log_response(config: KainguruConfig, response: httpx.Response) -> None:
|
|
83
|
+
if not config.debug:
|
|
84
|
+
return
|
|
85
|
+
logger.debug(
|
|
86
|
+
"<-- %s %s (%s) %s",
|
|
87
|
+
response.status_code,
|
|
88
|
+
response.request.url,
|
|
89
|
+
response.elapsed,
|
|
90
|
+
response.text,
|
|
91
|
+
)
|
|
92
|
+
|
|
31
93
|
|
|
32
94
|
def _headers(config: KainguruConfig, api_key: str | None) -> dict[str, str]:
|
|
33
95
|
headers = {"Accept": "application/json"}
|
|
@@ -142,6 +204,7 @@ class Transport:
|
|
|
142
204
|
headers = _headers(self._config, api_key)
|
|
143
205
|
last_exc: Exception | None = None
|
|
144
206
|
for attempt in range(self._config.max_retries + 1):
|
|
207
|
+
_log_request(self._config, method, url, headers, params, json, attempt)
|
|
145
208
|
try:
|
|
146
209
|
response = self._client.request(
|
|
147
210
|
method, url, params=params, json=json, headers=headers
|
|
@@ -154,6 +217,7 @@ class Transport:
|
|
|
154
217
|
) from exc
|
|
155
218
|
time.sleep(_retry_delay(attempt, None, self._config.retry_base_delay))
|
|
156
219
|
continue
|
|
220
|
+
_log_response(self._config, response)
|
|
157
221
|
if _is_retriable_status(response.status_code) and attempt < self._config.max_retries:
|
|
158
222
|
time.sleep(_retry_delay(attempt, response, self._config.retry_base_delay))
|
|
159
223
|
continue
|
|
@@ -184,6 +248,7 @@ class AsyncTransport:
|
|
|
184
248
|
headers = _headers(self._config, api_key)
|
|
185
249
|
last_exc: Exception | None = None
|
|
186
250
|
for attempt in range(self._config.max_retries + 1):
|
|
251
|
+
_log_request(self._config, method, url, headers, params, json, attempt)
|
|
187
252
|
try:
|
|
188
253
|
response = await self._client.request(
|
|
189
254
|
method, url, params=params, json=json, headers=headers
|
|
@@ -196,6 +261,7 @@ class AsyncTransport:
|
|
|
196
261
|
) from exc
|
|
197
262
|
await asyncio.sleep(_retry_delay(attempt, None, self._config.retry_base_delay))
|
|
198
263
|
continue
|
|
264
|
+
_log_response(self._config, response)
|
|
199
265
|
if _is_retriable_status(response.status_code) and attempt < self._config.max_retries:
|
|
200
266
|
await asyncio.sleep(_retry_delay(attempt, response, self._config.retry_base_delay))
|
|
201
267
|
continue
|
|
@@ -12,7 +12,7 @@ from ._config import (
|
|
|
12
12
|
DEFAULT_TIMEOUT,
|
|
13
13
|
KainguruConfig,
|
|
14
14
|
)
|
|
15
|
-
from ._transport import AsyncTransport
|
|
15
|
+
from ._transport import AsyncTransport, enable_debug_logging
|
|
16
16
|
from .resources import AsyncExecutionsResource, AsyncFineTuningResource
|
|
17
17
|
|
|
18
18
|
|
|
@@ -39,6 +39,7 @@ class AsyncKainguruClient:
|
|
|
39
39
|
timeout: float = DEFAULT_TIMEOUT,
|
|
40
40
|
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
41
41
|
retry_base_delay: float = DEFAULT_RETRY_BASE_DELAY,
|
|
42
|
+
debug: bool = False,
|
|
42
43
|
http_client: httpx.AsyncClient | None = None,
|
|
43
44
|
) -> None:
|
|
44
45
|
self._config = KainguruConfig.resolve(
|
|
@@ -47,7 +48,10 @@ class AsyncKainguruClient:
|
|
|
47
48
|
timeout=timeout,
|
|
48
49
|
max_retries=max_retries,
|
|
49
50
|
retry_base_delay=retry_base_delay,
|
|
51
|
+
debug=debug,
|
|
50
52
|
)
|
|
53
|
+
if self._config.debug:
|
|
54
|
+
enable_debug_logging()
|
|
51
55
|
client = http_client or httpx.AsyncClient(
|
|
52
56
|
base_url=self._config.base_url, timeout=self._config.timeout
|
|
53
57
|
)
|
|
@@ -12,7 +12,7 @@ from ._config import (
|
|
|
12
12
|
DEFAULT_TIMEOUT,
|
|
13
13
|
KainguruConfig,
|
|
14
14
|
)
|
|
15
|
-
from ._transport import Transport
|
|
15
|
+
from ._transport import Transport, enable_debug_logging
|
|
16
16
|
from .resources import ExecutionsResource, FineTuningResource
|
|
17
17
|
|
|
18
18
|
|
|
@@ -39,6 +39,7 @@ class KainguruClient:
|
|
|
39
39
|
timeout: float = DEFAULT_TIMEOUT,
|
|
40
40
|
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
41
41
|
retry_base_delay: float = DEFAULT_RETRY_BASE_DELAY,
|
|
42
|
+
debug: bool = False,
|
|
42
43
|
http_client: httpx.Client | None = None,
|
|
43
44
|
) -> None:
|
|
44
45
|
self._config = KainguruConfig.resolve(
|
|
@@ -47,7 +48,10 @@ class KainguruClient:
|
|
|
47
48
|
timeout=timeout,
|
|
48
49
|
max_retries=max_retries,
|
|
49
50
|
retry_base_delay=retry_base_delay,
|
|
51
|
+
debug=debug,
|
|
50
52
|
)
|
|
53
|
+
if self._config.debug:
|
|
54
|
+
enable_debug_logging()
|
|
51
55
|
client = http_client or httpx.Client(
|
|
52
56
|
base_url=self._config.base_url, timeout=self._config.timeout
|
|
53
57
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|