Python SDK
The warmhub package provides synchronous and asynchronous Python clients for
reading, writing, and navigating WarmHub repositories. It supports Python 3.10
and later.
Installation, tokens, client options and error handling are shared with the TypeScript SDK and covered once in the SDK Overview — pick its Python tab. In short:
pip install warmhubexport WH_TOKEN="wh_..."See Creating a personal access token if you need a token.
A first read and write
Section titled “A first read and write”from warmhub import WarmHubClient
with WarmHubClient.from_env() as client: sensors = client.repository("acme/sensors")
page = sensors.things.head(shape="Reading", limit=5) for item in page.items: print(item.wref, item.version, item.data)
batch = sensors.batch(message="seed a reading") batch.add(name="probe-1", shapes=["Reading"], data={"temp_celsius": 21.4}) result = batch.commit() print(result.operation_count)client.repository("org/repo") binds a repository handle, so later calls do not
repeat the organization and repository names. batch.add(...) only queues an
operation; batch.commit() is the line that sends it. Every add states the
Shapes the Thing declares — see Write Methods for the
other ways to write.
Sync or async
Section titled “Sync or async”Use WarmHubClient in ordinary
synchronous programs, as above.
AsyncWarmHubClient exposes
the same repository paths and arguments for async applications:
from warmhub import AsyncWarmHubClient
async with AsyncWarmHubClient.from_env() as client: sensors = client.repository("acme/sensors") page = await sensors.things.head(shape="Reading", limit=5)
batch = sensors.batch(message="seed a reading") batch.add(name="probe-2", shapes=["Reading"], data={"temp_celsius": 19.8}) result = await batch.commit()from_env() reads WH_TOKEN and WARMHUB_API_URL. The ordinary constructors
do not read credentials from the environment; pass access_token= when explicit
configuration is preferable.
Three rules worth knowing
Section titled “Three rules worth knowing”Payload keys are never renamed. Method arguments are snake_case, but keys
inside data are stored exactly as written. If a stored field is called
probeId, a typed Python payload must also call it probeId.
UNSET is not None. Optional parameters default to UNSET, which
leaves the field out of the request. Don’t pass None to mean “omitted”: most
optional parameters don’t accept it, and a None that reaches the request is
sent as JSON null, which the server rejects for those fields.
Not every error is a WarmHubError. Some mistakes are caught before any
request is sent, and how they surface depends on what was wrong:
- A wrong argument — an unknown keyword, a missing required one, or both
run_id=anddelivery_id=— raises Python’s ownTypeError. - A malformed repository locator, such as
client.repository("acme"), raisesValueError. - An operation the SDK can check locally — an add with no Shapes, or with both
shapes=andshapeless=True— raisesWriteOperationError, aWarmHubError.
Everything the server decides is a WarmHubError; branch on err.kind. See
Error Handling.
Where to go next
Section titled “Where to go next”Task guides walk through common jobs end to end:
- Bootstrap a repository — shapes, things, then assertions.
- Paginate with the
_itermethods. - Keep a local cache with change drains.
- Act as another principal.
- Run an action-runner loop.
Concepts shared with TypeScript: Write Methods, Repository Checkpoints, and Repo Statistics.
Reference: the Python SDK reference lists every
public name you can import from warmhub.
Client namespace methods take an
organization and repository explicitly;
repository-bound methods omit
them after client.repository("org/repo"). Sync and async signatures appear
together, so porting a call between the two needs one page.
To export a repository from Python, see Repository Checkpoints.