XCAICX docs Product Contact

Python API reference

A ctypes binding over the same C ABI. Same engine, same behaviour — not a reimplementation that can drift.

python
import xcaicx
xcaicx.version()          # "1.0.0"

The shared library is found on the default loader path, or via XCAICX_LIBRARY.


Engine#

python
xcaicx.Engine(*,
    license_token: str | None = None,
    license_path: str | None = None,
    license_pubkey: str | None = None,
    state_dir: str = "/var/lib/xcaicx",
    model_dir: str | None = None,
    modules: Module | int = 0,
    backend: Backend = Backend.AUTO,
    num_threads: int = 0,
    log_level: LogLevel = LogLevel.INFO,
    cloud_endpoint: str | None = None,
    heartbeat_seconds: int = 3600,
    offline: bool = False)

All arguments are keyword-only. Provide exactly one of license_token / license_path.

Raises LicenseError or EntitlementError at construction if the licence is unusable — failing at startup rather than mid-shift is deliberate.

Methods and properties#

MemberReturnsNotes
licenseLicenseSnapshot of the current licence state
active_modules()ModuleModules actually running
heartbeat()NoneForces a licensing/metering round trip; no-op when offline
stream(name, ...)StreamOpens a stream
close()NoneCloses streams and flushes metering
__enter__ / __exit__Use as a context manager
python
with xcaicx.Engine(license_path="unit.token", state_dir="./state") as eng:
    ...

close() is idempotent, and __del__ calls it — but relying on the garbage collector to flush your metering is relying on the interpreter's shutdown order. Use the context manager.


Engine.stream()#

python
eng.stream(name: str = "stream", *,
           modules: Module | int = 0,
           detect_threshold: float = 0.35,
           nms_threshold: float = 0.45,
           detect_every_n: int = 1) -> Stream

name is used in logs and in metering attribution. modules = 0 means all engine modules.


Stream#

MethodSignature
processprocess(data, *, width, height, fmt, pts_us=0, frame_id=0) -> Result
submitsubmit(data, *, width, height, fmt, pts_us=0, frame_id=0) -> None
poll`poll(timeout_ms=0) -> ResultNone`
add_zoneadd_zone(name, points, dwell_seconds=0) -> int
add_lineadd_line(name, a, b) -> int
closeclose() -> None

data is anything supporting the buffer protocol: bytes, bytearray, memoryview, or a numpy array. numpy is not a dependency — it simply works if present.

python
result = s.process(frame_bgr, width=1920, height=1080,
                   fmt=xcaicx.PixelFormat.BGR8, pts_us=pts, frame_id=n)

points for add_zone is a sequence of (x, y) tuples normalised to [0,1]. a and b for add_line are single (x, y) tuples.

poll() returns None when nothing is ready — it does not raise. submit() raises LimitError under backpressure; drop the frame.


Result types#

Result#

AttributeType
frame_idint
pts_usint
detectionslist[Detection]
eventslist[Event]
inference_msfloat
total_msfloat

Unlike the C API, Python results are copies — they stay valid after the next call.

Detection#

AttributeTypeNotes
boxBoxNormalised
scorefloat
class_idint
class_namestrperson, vehicle, object, defect, ppe_violation, plate
track_idint-1 if untracked
sourceModuleWhich module produced it
text`str \None`ANPR plate text
text_scorefloat

Box#

python
box.x, box.y, box.w, box.h          # normalised floats
box.to_pixels(width, height)        # -> (x, y, w, h) ints

Event#

AttributeType
kindEventKind
track_idint
zone_idint
zone_name`str \None`
detail`str \None`
scorefloat
pts_usint

License#

AttributeType
stateLicenseState
license_id, sku, customer_id, device_idstr
batch_id`str \None`
entitlementsModule
max_streams, max_fps_per_streamint
issued_at, expires_at, seconds_remaining, grace_daysint
metered_inferences, metered_stream_secondsint
is_usablebool — state is VALID or GRACE
perpetualboolexpires_at == 0
python
lic = eng.license
if not lic.is_usable:
    raise SystemExit(f"licence {lic.state.name}")
if lic.state is xcaicx.LicenseState.GRACE:
    warn(f"expired, {lic.seconds_remaining}s of grace left")

Enumerations#

python
class Module(enum.IntFlag):       DETECT, DEFECT, PPE, ANPR
class PixelFormat(enum.IntEnum):  RGB8, BGR8, GRAY8, NV12, I420
class EventKind(enum.IntEnum):    NONE, ZONE_ENTER, ZONE_EXIT, LINE_CROSS,
                                  DWELL_EXCEEDED, PPE_VIOLATION, DEFECT_FOUND, PLATE_READ
class LicenseState(enum.IntEnum): INVALID, VALID, GRACE, EXPIRED, REVOKED
class Backend(enum.IntEnum):      AUTO, REFERENCE, ORT_CPU, ORT_CUDA, TENSORRT,
                                  OPENVINO, RKNN, HAILO
class LogLevel(enum.IntEnum):     OFF, ERROR, WARN, INFO, DEBUG

Module is an IntFlag, so entitlements compose and test naturally:

python
if xcaicx.Module.PPE in eng.license.entitlements:
    ...
modules = xcaicx.Module.DETECT | xcaicx.Module.PPE

Exceptions#

text
RuntimeError
└── XcaicxError          .status: int, .detail: str
    ├── LicenseError     any licence-state failure
    ├── EntitlementError module not in SKU
    └── LimitError       stream/fps/quota cap, queue-full backpressure
python
try:
    result = s.process(frame, width=w, height=h, fmt=xcaicx.PixelFormat.BGR8)
except xcaicx.LimitError:
    dropped += 1                      # backpressure or quota
except xcaicx.LicenseError as exc:
    disable_analytics()               # keep recording
    alert(f"licence: {exc} (status {exc.status})")

.status is the numeric xcaicx_status, so it maps directly onto the status-code table.


Module-level#

python
xcaicx.version() -> str

Returns the library version string. Also the cheapest check that the shared library is loadable at all — call it once at startup and fail loudly if it raises.


Notes on the binding#

  • Strings passed into the engine are retained by the binding for the lifetime of the object. ctypes does not keep the temporaries produced by .encode() alive, and a config struct pointing at freed memory is the kind of bug that reproduces only under load.
  • Streams are tracked by their engine and closed when the engine closes, so a forgotten close() on a stream is not a leak.
  • Every call maps to exactly one C call. There is no caching layer and no reimplemented logic, which is why the binding cannot drift from the C behaviour.

Next#

Commercial software. Use requires a valid XCAICX licence token. Questions an integrator cannot answer from this page belong in an email to [email protected] — and, usually, in a fix to this page.

© 2026 AZMX AI · xcaicx.com