drukbox-python-sdk 0.0.5__tar.gz → 0.0.6__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.
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/PKG-INFO +1 -1
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/pyproject.toml +1 -1
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/src/drukbox_sdk/__init__.py +2 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/src/drukbox_sdk/api.py +9 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/src/drukbox_sdk/exceptions.py +9 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/tests/test_api.py +23 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/.github/workflows/on-main-merge.yml +0 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/.github/workflows/on-pull-request.yml +0 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/.github/workflows/release.yml +0 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/.gitignore +0 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/AGENTS.md +0 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/README.md +0 -0
- {drukbox_python_sdk-0.0.5 → drukbox_python_sdk-0.0.6}/tests/__init__.py +0 -0
|
@@ -18,6 +18,7 @@ from .exceptions import (
|
|
|
18
18
|
SandboxProvisioningError,
|
|
19
19
|
SandboxResponseError,
|
|
20
20
|
SandboxUnavailableError,
|
|
21
|
+
SandboxValidationError,
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
__all__ = [
|
|
@@ -32,4 +33,5 @@ __all__ = [
|
|
|
32
33
|
"SandboxProvisioningError",
|
|
33
34
|
"SandboxResponseError",
|
|
34
35
|
"SandboxUnavailableError",
|
|
36
|
+
"SandboxValidationError",
|
|
35
37
|
]
|
|
@@ -45,6 +45,7 @@ from .exceptions import (
|
|
|
45
45
|
SandboxProvisioningError,
|
|
46
46
|
SandboxResponseError,
|
|
47
47
|
SandboxUnavailableError,
|
|
48
|
+
SandboxValidationError,
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
# Explicit pool budget. The httpx defaults (100 / 20) are plenty for
|
|
@@ -350,6 +351,14 @@ class SandboxAPI:
|
|
|
350
351
|
if response.status_code == 503:
|
|
351
352
|
raise SandboxUnavailableError(json_response.get("detail", "service unavailable"))
|
|
352
353
|
|
|
354
|
+
if response.status_code == 422:
|
|
355
|
+
# FastAPI's 422 detail is a list of error dicts; join the messages
|
|
356
|
+
# so it reads as a line, not a raw list repr.
|
|
357
|
+
detail = json_response.get("detail", "validation error")
|
|
358
|
+
if isinstance(detail, list):
|
|
359
|
+
detail = "; ".join(item.get("msg", "") for item in detail) or "validation error"
|
|
360
|
+
raise SandboxValidationError(detail)
|
|
361
|
+
|
|
353
362
|
if response.status_code >= 400:
|
|
354
363
|
raise SandboxResponseError(json_response.get("detail", "error"))
|
|
355
364
|
return json_response
|
|
@@ -50,5 +50,14 @@ class SandboxProvisioningError(SandboxAPIError):
|
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
52
|
|
|
53
|
+
class SandboxValidationError(SandboxAPIError):
|
|
54
|
+
"""422 — the service rejected the request payload as invalid.
|
|
55
|
+
|
|
56
|
+
e.g. an env key that isn't a valid environment-variable name, or a
|
|
57
|
+
proxy target URL carrying a path or credentials. The request is
|
|
58
|
+
malformed, so retrying it unchanged won't help — fix the input.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
53
62
|
class SandboxResponseError(SandboxAPIError):
|
|
54
63
|
"""Everything else the service returned that the SDK doesn't classify."""
|
|
@@ -31,6 +31,7 @@ from drukbox_sdk import (
|
|
|
31
31
|
SandboxProvisioningError,
|
|
32
32
|
SandboxResponseError,
|
|
33
33
|
SandboxUnavailableError,
|
|
34
|
+
SandboxValidationError,
|
|
34
35
|
)
|
|
35
36
|
|
|
36
37
|
BASE_URL = "https://sandbox.test"
|
|
@@ -333,6 +334,28 @@ async def test_409_raises_sandbox_conflict_error(api: SandboxAPI):
|
|
|
333
334
|
await api.delete_host(host_id)
|
|
334
335
|
|
|
335
336
|
|
|
337
|
+
@respx.mock
|
|
338
|
+
async def test_422_raises_sandbox_validation_error(api: SandboxAPI):
|
|
339
|
+
# FastAPI's 422 detail is a list of error dicts; the SDK flattens it to a
|
|
340
|
+
# readable line and raises the dedicated validation error (don't-retry).
|
|
341
|
+
respx.post(f"{BASE_URL}/hosts").mock(
|
|
342
|
+
return_value=httpx.Response(
|
|
343
|
+
422,
|
|
344
|
+
json={
|
|
345
|
+
"detail": [
|
|
346
|
+
{
|
|
347
|
+
"loc": ["body", "env"],
|
|
348
|
+
"msg": "env keys must be valid environment variable names: FOO BAR",
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
},
|
|
352
|
+
),
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
with pytest.raises(SandboxValidationError, match="env keys must be valid"):
|
|
356
|
+
await api.create_host(env={"FOO BAR": "x"})
|
|
357
|
+
|
|
358
|
+
|
|
336
359
|
@respx.mock
|
|
337
360
|
async def test_500_raises_sandbox_response_error(api: SandboxAPI):
|
|
338
361
|
respx.get(f"{BASE_URL}/hosts").mock(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|