SPEClient
spe.client.SPEClient is a thin, typed client for a running SPE engine server. It is a context manager.
from spe import SPEClient
with SPEClient("http://127.0.0.1:5000") as client:
client.health()
Constructor
SPEClient(
base_url: str = "http://127.0.0.1:5000",
*,
timeout: float = 30.0,
retries: int = 2,
backoff: float = 0.5,
user_agent: str | None = None,
transport: Transport | None = None,
) -> None
| Argument | Description |
|---|---|
base_url | Root URL of the server; must be a non-empty string. |
timeout | Per-request timeout in seconds. |
retries | Automatic retries for idempotent requests on connection loss. |
backoff | Base backoff delay (seconds); doubles each retry. |
user_agent | Optional User-Agent header. |
transport | Custom Transport; defaults to the best available backend. |
Raises SPEValidationError when base_url is empty or not a string.
Lifecycle
| Member | Description |
|---|---|
base_url | Normalized base URL (no trailing slash). |
__enter__ / __exit__ | Context-manager protocol. |
close() | Release transport resources. |
SPEClient.from_env(variable="SPE_API_URL", **kwargs) | Build from an environment variable. |
Health and state
| Method | Route | Returns |
|---|---|---|
health() | GET /health | Raw payload. |
get_state() | GET /api/state | Raw payload. |
Sources
| Method | Route | Returns |
|---|---|---|
create_source(source, *, filename=None, source_type="image", mime_type=None) | POST /api/sources | response["source"]. |
get_source(source_id) | GET /api/sources/{id} | response["source"]. |
delete_source(source_id) | DELETE /api/sources/{id} | None. |
source_media_url(source_id) | — | Absolute media URL string. |
get_source_media(source_id) | GET /api/sources/{id}/media | Raw bytes. |
source may be bytes, bytearray, memoryview, str/os.PathLike path, or a binary file object.
Calibration
| Method | Route |
|---|---|
calibrate(source_points, source_width, source_height, *, reference_width=1000, reference_height=600, units="normalized", rows=3, columns=3) | POST /api/calibration |
get_calibration() | GET /api/calibration → response["calibration"] |
update_calibration(...) (same signature as calibrate) | PUT /api/calibration |
delete_calibration() | DELETE /api/calibration |
ROI and grid
| Method | Route | Returns |
|---|---|---|
get_roi() | GET /api/roi | response["roi"]. |
create_roi(points) | POST /api/roi | response["roi"]. |
update_roi(points) | PUT /api/roi | response["roi"]. |
delete_roi() | DELETE /api/roi | None. |
get_grid() | GET /api/grid | response["grid"]. |
set_grid(rows, columns) | PUT /api/grid | response["grid"]. |
delete_grid() | DELETE /api/grid | None. |
Spatial queries
transform_points
transform_points(
points,
*,
homography=None,
calibration=None,
direction="image_to_reference",
) -> dict
Posts to POST /api/calibration/transform. Provide a homography or a calibration mapping.
inspect_point
inspect_point(
point=None,
*,
x=None, y=None,
calibration=None,
grid=None,
source_dimensions=None,
spatial_state=None,
) -> dict
Posts to POST /api/spatial/inspect-point. Supply either point or both x and y (otherwise SPEValidationError). When spatial_state is given it is used directly; otherwise calibration/grid/source_dimensions are sent.
Rendering
| Method | Route |
|---|---|
generate_grid(image, *, filename=None, rows=8, columns=12, line_thickness=1, line_color="#a8f35b", show_coordinates=True, source_type="image", fps=None, frame_count=None) | POST /api/grid |
generate_calibrated_grid(image, homography, *, filename=None, rows=4, columns=6, reference_width=1000, reference_height=600, source_points=None, show_grid=True, show_roi=True, line_color="#a8f35b", roi_color="#ff3b30", overlay_only=False) | POST /api/calibrated-grid |
video_metadata(video, *, filename=None) | POST /api/video/metadata |
The rendering methods return {"image": ..., "metadata": {...}}.
Models
| Method | Route | Returns |
|---|---|---|
list_models() | GET /api/models | response["models"]. |
models() | GET /api/models | Typed ModelDescriptor objects. |
get_model(model_id) | GET /api/models/{id} | response["model"]. |
model_status(model_id) | GET /api/models/{id}/status | Raw payload. |
load_model(model_id) | POST /api/models/{id}/load | Raw payload. |
unload_model(model_id) | POST /api/models/{id}/unload | Raw payload. |
model_classes(model_id) | GET /api/models/{id}/classes | response["classes"]. |
Analysis
detect
detect(*, model_id="model-a", confidence=0.4, classes=None, source_id=None) -> dict
POST /api/analysis/detect.
detect_frame
detect_frame(
frame,
*,
filename="frame.jpg",
model_id="model-a",
confidence=0.4,
classes=None,
analysis_id="analysis",
source_id="source",
timestamp=0.0,
frame_index=0,
tracking=False,
tracking_mode=None,
target_track_id=None,
target_detection=None,
inference_context=None,
spatial_context=None,
interval_ms=None,
effective_fps=None,
) -> dict
POST /api/analysis/detect-frame. Detects and (optionally) tracks, spatializes, and timestamps a single frame.
Session methods
| Method | Route | Returns |
|---|---|---|
start_analysis_session(analysis_id, source_id, model, *, spatial_context=None) | POST /api/analysis/session/start | response["analysis"]. |
update_analysis_status(analysis_id, status="running", *, inference_fps=None, interval_ms=None) | PATCH /api/analysis/session/status | response["analysis"]. |
complete_analysis_session(analysis_id, status="complete") | POST /api/analysis/session/complete | Raw payload. |
AsyncSPEClient
spe.aio.AsyncSPEClient mirrors SPEClient. Every method is a coroutine; the synchronous client runs in a worker thread (asyncio.to_thread).
import asyncio
from spe import AsyncSPEClient
async def main() -> None:
async with AsyncSPEClient("http://127.0.0.1:5000") as client:
await client.health()
asyncio.run(main())
Constructor arguments are forwarded verbatim to SPEClient. Additional members:
| Member | Description |
|---|---|
async __aenter__ / __aexit__ | Async context manager. |
await aclose() | Close the underlying client. |
AsyncSPEClient.from_env(variable="SPE_API_URL", **kwargs) | Build from an environment variable. |
base_url (property) | The underlying base URL. |
Async methods (all coroutines; signatures match SPEClient):
health, get_state, create_source, get_source, delete_source, source_media_url (sync), get_source_media, calibrate, get_calibration, update_calibration, delete_calibration, get_roi, create_roi, delete_roi, get_grid, set_grid, delete_grid, transform_points, inspect_point, generate_grid, generate_calibrated_grid, video_metadata, list_models, get_model, model_status, load_model, unload_model, model_classes, detect, detect_frame, start_analysis_session, update_analysis_status, complete_analysis_session.
Transports
spe.transport. A transport performs exactly one request and never retries; retries, timeouts, and error mapping live in the client. Transport-level failures are raised as SPEConnectionError or SPETimeoutError.
Transport (protocol)
class Transport(Protocol):
def request(
self,
method: str,
url: str,
*,
headers: Mapping[str, str],
data: bytes | None,
timeout: float,
) -> tuple[int, Mapping[str, str], bytes]: ...
def close(self) -> None: ...
Backends
| Class | Backing library | Notes |
|---|---|---|
UrllibTransport | standard library urllib.request | Default; zero dependencies. |
RequestsTransport | requests | Used when installed (not exported at package top level). |
HttpxTransport | httpx | Preferred when installed (not exported at package top level). |
get_default_transport
get_default_transport(prefer: str | None = None) -> Transport
With prefer=None, returns HttpxTransport if httpx is importable, then RequestsTransport if requests is importable, otherwise UrllibTransport. Pass "urllib", "requests", or "httpx" to force a backend; an unknown name raises ValueError.
Exceptions
All errors derive from SPEError.
| Exception | Base classes | Meaning |
|---|---|---|
SPEError | Exception | Base class for every SDK error. |
SPEValidationError | SPEError, ValueError | Invalid geometry or parameters. |
SPEEngineError | SPEError, RuntimeError | Local processing cannot complete. |
SPEModelUnavailableError | SPEEngineError | A model has no usable runtime. |
SPETransportError | SPEError, RuntimeError | Base for transport failures. |
SPEConnectionError | SPETransportError | The server cannot be reached. |
SPETimeoutError | SPETransportError | A request exceeded its timeout. |
SPEAPIError | SPEError | The server returned an error. |
SPEBadRequestError | SPEAPIError | HTTP 400: invalid request payload. |
SPEAuthenticationError | SPEAPIError | HTTP 401/403: missing or rejected credentials. |
SPENotFoundError | SPEAPIError | HTTP 404: the resource does not exist. |
SPEConflictError | SPEAPIError | HTTP 409: the server state rejected the request. |
SPERateLimitError | SPEAPIError | HTTP 429: the client is being throttled. |
SPEServerError | SPEAPIError | HTTP 5xx: a server-side failure. |
SPEAPIError exposes status_code: int | None, payload: Any | None, url: str | None, retry_after: float | None, and response_headers: dict. The status-specific subclasses keep except SPEAPIError handlers valid.