drukbox-python-sdk 0.3.0__py3-none-any.whl → 0.5.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: drukbox-python-sdk
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: Async Python client for Drukbox.
5
5
  Project-URL: Homepage, https://github.com/clawhaven/drukbox-python-sdk
6
6
  Project-URL: Repository, https://github.com/clawhaven/drukbox-python-sdk
@@ -59,6 +59,8 @@ finally:
59
59
  few minutes worst case. The SDK's default `timeout` (300s) covers this. Pass
60
60
  an `idempotency_key` for retry safety: a retry with the same key after a
61
61
  successful provision returns the original host instead of creating a duplicate.
62
+ A provider at its host limit raises `SandboxCapacityError`, a
63
+ `SandboxUnavailableError` whose `retry_after` gives the seconds to wait.
62
64
 
63
65
  `SandboxAPI.from_env(prefix="SANDBOX_")` reads
64
66
  `SANDBOX_SERVICE_URL`, `SANDBOX_SERVICE_TOKEN`, and optional
@@ -0,0 +1,7 @@
1
+ drukbox_sdk/__init__.py,sha256=OgssAANGnl49_1N_EKMXSDlgWfedO9jUAnLVxgkJY2Q,1066
2
+ drukbox_sdk/api.py,sha256=z-Sjh_rdqIFpMgzfG7_RktxbH6wS8rToHfy0B8FNZkI,24668
3
+ drukbox_sdk/exceptions.py,sha256=0CKbb0Ec4RSWPB8t31WJgO1yQQ10BwTPqoqS1_EieB4,2599
4
+ drukbox_python_sdk-0.5.0.dist-info/METADATA,sha256=mrbJKSw-RuyIXSPaxtKn6DDYqP9Y7IBlw0NvLetTL-0,6734
5
+ drukbox_python_sdk-0.5.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
6
+ drukbox_python_sdk-0.5.0.dist-info/licenses/LICENSE,sha256=zM66rWL3BWGJBa_mZPnM0WUomSSZ1xtWVtGQovQ71M8,1078
7
+ drukbox_python_sdk-0.5.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.32.0
2
+ Generator: hatchling 1.32.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
drukbox_sdk/__init__.py CHANGED
@@ -19,6 +19,7 @@ from .api import (
19
19
  from .exceptions import (
20
20
  SandboxAPIError,
21
21
  SandboxAuthError,
22
+ SandboxCapacityError,
22
23
  SandboxConflictError,
23
24
  SandboxNotFoundError,
24
25
  SandboxProvisioningError,
@@ -36,6 +37,7 @@ __all__ = [
36
37
  "SandboxAPI",
37
38
  "SandboxAPIError",
38
39
  "SandboxAuthError",
40
+ "SandboxCapacityError",
39
41
  "SandboxConflictError",
40
42
  "SandboxHost",
41
43
  "SandboxNotFoundError",
drukbox_sdk/api.py CHANGED
@@ -47,6 +47,7 @@ import httpx
47
47
 
48
48
  from .exceptions import (
49
49
  SandboxAuthError,
50
+ SandboxCapacityError,
50
51
  SandboxConflictError,
51
52
  SandboxNotFoundError,
52
53
  SandboxProvisioningError,
@@ -197,7 +198,8 @@ class DoctorReport:
197
198
 
198
199
  ok: bool
199
200
  active_provider: str
200
- tailscale_enabled: bool
201
+ # Whether the active provider's hosts join the tailnet.
202
+ tailnet: bool
201
203
  checks: list[DoctorCheck]
202
204
 
203
205
 
@@ -435,14 +437,15 @@ class SandboxAPI:
435
437
  base_image: str | None = None,
436
438
  label: str | None = None,
437
439
  ) -> SandboxTemplate:
438
- """Start a template build and return immediately.
439
-
440
- The service responds 202 with ``status="building"``. Poll
441
- :meth:`get_template` until the status becomes ``"available"`` or
442
- ``"failed"``. A failed record carries the reason in
443
- ``last_error``. A repeated post with the same provider, base
444
- image, and setup script returns the existing record without a
445
- rebuild.
440
+ """Start a template build.
441
+
442
+ The service pulls the base image, then responds 202 with
443
+ ``status="building"``. Poll :meth:`get_template` until the status
444
+ becomes ``"available"`` or ``"failed"``. A failed record carries the
445
+ reason in ``last_error``. A repeated post with the same provider,
446
+ base image digest, and setup script returns the existing record. A
447
+ ``"failed"`` record builds again and keeps its ``last_error`` until
448
+ that build ends.
446
449
  """
447
450
 
448
451
  payload: dict[str, Any] = {"setup_script": setup_script}
@@ -488,7 +491,8 @@ class SandboxAPI:
488
491
  return DoctorReport(
489
492
  ok=data["ok"],
490
493
  active_provider=data["active_provider"],
491
- tailscale_enabled=data["tailscale_enabled"],
494
+ # drukbox before "Join the tailnet per provider" sent tailscale_enabled.
495
+ tailnet=data["tailnet"] if "tailnet" in data else data["tailscale_enabled"],
492
496
  checks=[DoctorCheck(**check) for check in data["checks"]],
493
497
  )
494
498
 
@@ -614,6 +618,11 @@ class SandboxAPI:
614
618
  raise SandboxProvisioningError(json_response.get("detail", "provisioning failed"))
615
619
 
616
620
  if response.status_code == 503:
621
+ if json_response.get("error_code") == "CAPACITY":
622
+ raise SandboxCapacityError(
623
+ json_response.get("detail", "provider at host limit"),
624
+ retry_after=int(response.headers["Retry-After"]),
625
+ )
617
626
  raise SandboxUnavailableError(json_response.get("detail", "service unavailable"))
618
627
 
619
628
  if response.status_code == 422:
drukbox_sdk/exceptions.py CHANGED
@@ -18,6 +18,18 @@ class SandboxUnavailableError(RuntimeError):
18
18
  """
19
19
 
20
20
 
21
+ class SandboxCapacityError(SandboxUnavailableError):
22
+ """503 — the provider is at its host limit.
23
+
24
+ ``retry_after`` is the service's ``Retry-After`` value in seconds:
25
+ wait at least that long before the next create.
26
+ """
27
+
28
+ def __init__(self, message: str, retry_after: int) -> None:
29
+ super().__init__(message)
30
+ self.retry_after = retry_after
31
+
32
+
21
33
  class SandboxAPIError(RuntimeError):
22
34
  """Base for any error the sandbox service returned via HTTP."""
23
35
 
@@ -1,7 +0,0 @@
1
- drukbox_sdk/__init__.py,sha256=bU2rOTzC3GMXSpiXvoMVwFOuKJUPZWSXhnteaRFxT_Y,1012
2
- drukbox_sdk/api.py,sha256=eoXXnK8mkrSK9Q4tRSuVbN-6mSjbBTTeEsH_jF3U_wY,24118
3
- drukbox_sdk/exceptions.py,sha256=Vzs4zVOywWsWfiZm6vgQ65ScI3Nn7zLGVj-8eT1YAR0,2224
4
- drukbox_python_sdk-0.3.0.dist-info/METADATA,sha256=KL-_BzJPSEVgimNohBs8BIxhwcU8dreFTdVSihBlUaI,6599
5
- drukbox_python_sdk-0.3.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
6
- drukbox_python_sdk-0.3.0.dist-info/licenses/LICENSE,sha256=zM66rWL3BWGJBa_mZPnM0WUomSSZ1xtWVtGQovQ71M8,1078
7
- drukbox_python_sdk-0.3.0.dist-info/RECORD,,