Python SDK
cheetah-client — install, connect, sync and async usage, typed responses, and error handling.
cheetah-client wraps the open REST API for Python ≥ 3.11, with synchronous and asynchronous variants of every method and Pydantic-typed responses.
Install#
Install from the cheetah-service repository, pinned to the release tag matching your cell:
pip install "cheetah-client @ git+https://github.com/CheetahEngineering/cheetah-service.git@v0.0.132#subdirectory=clients/python"
Or with uv:
uv add "cheetah-client @ git+https://github.com/CheetahEngineering/cheetah-service.git@v0.0.132#subdirectory=clients/python"
Pin the tag (@v0.0.132), not @main — main will move under you, and the tag is what keeps SDK and service versions aligned.
Connect#
from cheetah_client import CheetahClient
with CheetahClient("http://cheetah-cell.local:8000") as client:
print(client.health())
The constructor takes the cell's base URL and an optional timeout (seconds, default 30.0). The client is a context manager; outside a with block, call client.close() when done.
Sync and async#
Every method has an async twin with an _async suffix, and the client is also an async context manager:
import asyncio
from cheetah_client import CheetahClient
async def main() -> None:
async with CheetahClient("http://cheetah-cell.local:8000") as client:
page = await client.programs.list_all_runs_async(status="completed", limit=10)
print(page.total)
asyncio.run(main())
The public surface#
How the SDK maps onto the API reference:
| Method | Endpoint |
|---|---|
client.health() |
GET /health |
client.programs.list() · .get(program_id) |
GET /programs · GET /programs/{program_id} |
client.programs.list_all_runs(...) |
GET /runs — takes program_id, status, serial_number, updated_since, limit, offset |
client.programs.list_runs(program_id, ...) |
GET /programs/{program_id}/runs |
client.programs.get_run(run_id) · .get_active_run() |
GET /runs/{run_id} · GET /runs/active |
client.programs.get_run_quality_report(run_id) |
GET /runs/{run_id}/quality-report |
client.programs.download_cl_sweep(run_id, step_index) |
GET /runs/{run_id}/steps/{step_index}/cl_sweep.csv |
client.sensor.get_frame(frame_id) · .get_frame_files(frame_id) |
GET /sensor/frames/{frame_id} · …/files |
client.sensor.download_ply(frame_id, raw=False) |
GET …/file.ply (raw=True → …/file.raw.ply) — returns bytes |
client.sensor.download_png(frame_id, luminance=False) |
GET …/file.png (luminance=True → …/file.luminance.png) — returns bytes |
client.sensor.download_npy(frame_id) |
GET …/file.npy — returns bytes |
client.webhooks.list() · .get() · .create(...) · .update(...) · .delete() |
/webhooks management |
client.webhooks.test(webhook_id) |
POST /webhooks/{webhook_id}/test |
client.webhooks.list_deliveries(webhook_id, ...) · .get_delivery_detail(delivery_id) · .retry_delivery(delivery_id) |
Delivery log and replay |
The SDK exposes more than this — see scope for what that means.
Putting it together#
Recent inspection results with their QC outcomes:
from cheetah_client import CheetahClient
with CheetahClient("http://cheetah-cell.local:8000") as client:
page = client.programs.list_all_runs(status="completed", limit=10)
for run in page.runs:
report = client.programs.get_run_quality_report(run.id)
if report.quality_report:
print(run.serial_number, run.revision, report.quality_report.status)
Responses are Pydantic models — attribute access, IDE completion, and .model_dump() when you need a plain dict. For the production polling pattern behind this loop, see incremental sync.
Errors#
All SDK exceptions derive from cheetah_client.CheetahError:
| Exception | Raised when |
|---|---|
ConnectionError |
The cell can't be reached — network problem, not an API one |
APIError |
Any HTTP error; carries status_code, code, params from the error envelope |
NotFoundError |
404s — a subclass of APIError with resource and resource_id |
from cheetah_client import CheetahClient, NotFoundError
with CheetahClient("http://cheetah-cell.local:8000") as client:
try:
run = client.programs.get_run("0196a3f2-7c1e-7d2a-b3a4-9e8d1c2b3a4f")
except NotFoundError as e:
print(f"no such {e.resource}: {e.resource_id}")
Which failures are worth retrying is covered in Errors and retries.
Next#
- API reference — the schemas behind every typed response.
- Open REST API — polling and sync patterns to build with these methods.
- TypeScript SDK — the same surface for Node.