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.
Files changed (25) hide show
  1. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/PKG-INFO +10 -2
  2. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/README.md +8 -0
  3. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/pyproject.toml +1 -1
  4. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_config.py +3 -0
  5. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_transport.py +66 -0
  6. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/async_client.py +5 -1
  7. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/client.py +5 -1
  8. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/.gitignore +0 -0
  9. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/MAINTAINERS.md +0 -0
  10. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/Makefile +0 -0
  11. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/__init__.py +0 -0
  12. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_errors.py +0 -0
  13. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/_polling.py +0 -0
  14. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/models.py +0 -0
  15. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/py.typed +0 -0
  16. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/__init__.py +0 -0
  17. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/_common.py +0 -0
  18. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/executions.py +0 -0
  19. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/src/kainguru/resources/finetuning.py +0 -0
  20. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/conftest.py +0 -0
  21. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/resources/openapi.json +0 -0
  22. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/test_auth.py +0 -0
  23. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/test_executions.py +0 -0
  24. {kainguru_sdk-0.1.8.dev0 → kainguru_sdk-0.2.9.dev0}/tests/test_finetuning.py +0 -0
  25. {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.4
1
+ Metadata-Version: 2.5
2
2
  Name: kainguru-sdk
3
- Version: 0.1.8.dev0
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "kainguru-sdk"
7
- version = "0.1.8.dev0"
7
+ version = "0.2.9.dev0"
8
8
  description = "Python SDK for the Kainguru ML platform — run models and fine-tune them."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -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
  )