> ## Documentation Index
>
> Fetch the complete documentation index at: https://lithi.ai/llms.txt
>
> Use this file to discover all available pages before exploring further.

---
title: Use the Python client
description: >-
  How the released Python client is shaped: imports, submitting a task spec, awaiting
  a terminal state without blocking, canceling work, and reading a streamed result
  bundle.
route: /docs/compute/clients/python
page_id: docs-compute-clients-python
page_type: howTo
content_layer: guided documentation
surface_profile: guided_docs
audience: Python developers submitting Compute work from a service or notebook
voice: D
reader_question: How do I submit, await, cancel and read Compute work from Python?
primary_action: Check your client version against the compatibility matrix
source_locale: en-US
source_status: APPROVED
source_version: docs-compute-clients-python-en-us-2026-09-05-v1
last_updated: '2026-09-05'
robots: index
claim_registry_pinned: true
claim_registry_resync: "npm run governed:tsx -- scripts/build-compute-public-claim-registry.ts --write"
---

## Before you install

This page prints no package name. The released package, its version and the Python versions it is tested against are published on the compatibility matrix, because they move with each release.

Your base URL and current API version appear in the portal under developer settings, and in the API description you download.

Keep your work key in your operating system credential store or your team's secret manager. Pass the client a reference to it, never the secret itself.

## Imports and the call shape

The client mirrors the API namespaces, so a call site shows the authority it needs.

```python
# The import path for the released package is listed on the compatibility matrix.
client = lithi.Client(credential=credential_from_store())

quote = await client.work.quote(task_spec)
```

Work submission lives under `client.work`. Configuration, identities, sources, profiles and finance live under their own namespaces, and a work key cannot reach any of them.

Your `task_spec` carries the same seven objects everywhere: `workflow`, `input`, `parameters`, `quality`, `policy`, `output` and `limits`.

## Wait for a terminal state without blocking

Terminal states are `SUCCEEDED`, `PARTIAL`, `FAILED` and `CANCELLED`. Everything else means keep waiting.

```python
TERMINAL = {"SUCCEEDED", "PARTIAL", "FAILED", "CANCELLED"}

async def wait_for_terminal(client, job_id):
    while True:
        status = await client.work.status(job_id=job_id)
        if status.state in TERMINAL:
            return status
        await sleep_until(status.valid_until)
```

Wait on `valid_until` rather than a fixed interval. A read past its `valid_until` is stale, whatever your timer says.

## Cancel work you no longer want

Cancellation is a request, not an instant stop. The job moves to `CANCELLING`, then to `CANCELLED` once it settles.

Work already accepted before your request is charged under your applicable commercial policy. Read the receipt rather than assuming a canceled job costs nothing.

Cancel the job through the cancel operation. Ending your own Python task only ends your read.

## Read a streamed result bundle

Stream part files if the data is large, but treat them as incomplete until the manifest is present.

```python
manifest = await client.work.result(job_id=job_id)
# result-manifest.json is written last and binds every file, count and schema.

for part in manifest.data_parts:
    async for row in read_part(part):
        handle(row)
```

Accepted rows sit under `data/part-*`. Typed failures, abstentions and preserved disagreements sit in their own directories beside it, so read all four before you call a run clean.

Tabular output arrives with `lithi_status`, `lithi_result`, `lithi_error_code`, `lithi_confidence`, `lithi_evidence`, `lithi_verification` and `lithi_usage` appended.

## When something refuses

Each operation carries its own generated `error_schema`, so there is no one error table to import. Every refusal carries a safe reason and a non-empty next action.

Keep `EDGE_ABUSE_LIMITED`, `CANONICAL_ADMISSION_LIMITED`, `CANONICAL_BUDGET_EXHAUSTED` and `CELL_CAPACITY_UNAVAILABLE` in separate branches. Two of them describe authority, and no retry fixes those.

Confirm what your version supports on the [client compatibility matrix](/docs/compute/clients/compatibility), and see [what each file in a result bundle holds](/docs/compute/results/bundle-layout) before you parse one.
