First-party Python SDK for the Quantava REST API: robust workflow execution, polling, and parallel runs.
Project description
quantava
First-party Python SDK for the Quantava workflow platform. Trigger a deployed workflow, poll to a terminal state with backoff, return a typed result, and fan out many runs in parallel with bounded concurrency and partial-failure isolation.
- Async-first core with a synchronous facade — use whichever fits your code.
- Typed inputs inferred from each workflow's trigger schema.
- Tiny dependency surface:
httpx+pydanticv2.
Install
pip install quantava
# Server-Sent Events streaming support:
pip install "quantava[sse]"
Python 3.11-3.12.
Quickstart
No with block, no client to manage — fan out one workflow over many inputs and
print a summary:
import quantava as qv
batch = qv.run_many("wf_id", [{"x": 1}, {"x": 2}], max_concurrency=5, progress=True)
batch.print_summary()
A single run, waited to completion, returning its output:
import quantava as qv
output = qv.run_and_wait("wf_id", {"x": 1})
print(output)
These read your key from the environment (QUANTAVA_API_KEY) or accept it
explicitly: qv.run_and_wait("wf_id", {...}, api_key="qva_...").
Prerequisite: the API key must have the
workflows:executescope, or the trigger fails with aPermissionDeniedError. (ensure_deployed=Truealso needsworkflows:deploy.)
Authenticate
The SDK uses an API key (X-API-Key: qva_...). The base URL defaults to
https://quantava.io/api/v1; override it with the base_url argument or the
QUANTAVA_BASE_URL environment variable for self-host or staging.
export QUANTAVA_API_KEY=qva_your_key
# optional:
export QUANTAVA_BASE_URL=https://quantava.io/api/v1
Explicit client (streaming, reuse)
For repeated calls, streaming, or fine-grained control, construct a client once
and reuse it. The synchronous client uses a with block; the async client uses
async with.
from quantava import Quantava, WorkflowExecutionError
with Quantava.from_env() as q: # reads QUANTAVA_API_KEY / QUANTAVA_BASE_URL
execution = q.workflows.run("wf_id", pdf_url="https://example.com/a.pdf")
try:
output = execution.result(timeout=300) # waits to terminal, returns output_data
except WorkflowExecutionError as exc:
print(f"failed: {exc} (execution_id={exc.execution_id})")
else:
print(output)
import asyncio
from quantava import AsyncQuantava
async def main():
async with AsyncQuantava.from_env() as q:
execution = await q.workflows.run("wf_id", pdf_url="https://example.com/a.pdf")
output = await execution.result(timeout=300)
print(output)
asyncio.run(main())
You can also pass the key directly (Quantava(api_key="qva_...")) and cheaply
reconfigure a client with q.with_options(max_concurrency=20, timeout=60).
Typed inputs
Each workflow's trigger node declares an input schema (name, type, required, default, description). The SDK surfaces those as typed, validated parameters and catches mistakes before a wasted round-trip.
wf = q.workflows.get("wf_id")
for field in wf.inputs.fields:
print(field.name, field.json_type, "required" if field.required else "optional")
wf.inputs.is_free_form # True when no usable schema is declared
execution = wf.run(pdf_url="https://example.com/a.pdf", page={"n": 1})
Escape hatches: q.workflows.run(id, ..., validate=False) or
q.workflows.run_raw(id, input_data={...}) send arbitrary JSON untouched.
Note: Typed-input checks are client-side only. The Quantava server does not enforce the trigger schema — it accepts
input_dataverbatim. The SDK validation gives parity with the web run-form and catches obvious mistakes, but a server that accepts your input does not imply the schema matched.
Parallel execution
Fan out many runs with bounded concurrency, automatic retries, idempotency-safe triggers, and partial-failure isolation. Results are collected by default.
from quantava import AsyncQuantava, RunSpec
async with AsyncQuantava.from_env() as q:
batch = await q.run_parallel(
[
("wf_a", {"x": 1}),
("wf_b", {"x": 2}),
RunSpec(workflow_id="wf_c", input={"x": 3}, per_run_timeout=120),
],
max_concurrency=8, # None falls back to config.max_concurrency (default 8)
fail_fast=False, # collect-all default; True cancels remaining on first failure
timeout=600, # overall batch budget (None = no cap)
per_run_timeout=300, # per-run budget (None = poll to terminal)
progress=True,
)
batch.print_summary()
print(batch.ok, batch.failed, batch.outputs)
batch.raise_for_errors() # raises BatchError(failed) if any run failed
batch is a sequence of RunResult in input order — iterate it (for r in batch: r.ok / r.output / r.input / r.error) to map results back to jobs.
batch.outputs holds the successful outputs only, so it is not
positionally aligned with the input jobs.
The synchronous Quantava.run_parallel(...) / Quantava.run_many(...) drive the
same async engine on a background event-loop thread, so they work in plain
scripts and notebooks.
Errors
All exceptions import from quantava and derive from QuantavaError.
from quantava import (
QuantavaError, # base
APIError, # server error: status_code, code, message, details, request_id
AuthenticationError, # 401
PermissionDeniedError, # 403 (e.g. missing workflows:execute scope)
NotFoundError, # 404
ConflictError, # 409
ValidationError, # 400/422 -> .field_errors
RateLimitError, # 429 -> .retry_after, .limits
ServerError, # 5xx
ConnectionError, # network/transport
TimeoutError, # request-level timeout
WorkflowNotDeployedError,
WorkflowExecutionError, # .execution_id, .error_message, .request_id
ExecutionTimeout, # wait() exceeded timeout (no server-side cancel by default)
WorkflowInputError, # client-side input validation
BatchError, # aggregates failed RunResults
)
Catch what you care about and let the rest propagate:
import quantava as qv
from quantava import (
RateLimitError,
WorkflowExecutionError,
WorkflowInputError,
QuantavaError,
)
try:
output = qv.run_and_wait("wf_id", {"pdf_url": "https://example.com/a.pdf"})
except WorkflowInputError as exc: # client-side: bad/missing inputs
print(f"fix your inputs: {exc}")
except RateLimitError as exc: # 429 (auto-retried first; surfaced if exhausted)
print(f"rate limited, retry after {exc.retry_after}s")
except WorkflowExecutionError as exc: # the run reached a terminal failure
print(f"run {exc.execution_id} failed: {exc.error_message}")
except QuantavaError as exc: # anything else from the SDK
print(f"unexpected: {exc}")
The retry engine automatically retries RateLimitError (honoring Retry-After,
including HTTP-date values), ServerError 502/503/504, and connect/read timeouts
on idempotent reads. Everything else fails fast.
Examples
Runnable scripts live in examples/: quickstart_sync.py,
quickstart_async.py, and parallel.py.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quantava-0.2.0.tar.gz.
File metadata
- Download URL: quantava-0.2.0.tar.gz
- Upload date:
- Size: 37.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
659833ef0dccf61ded00e6416ddb45a41a4db5b8157a9d71144bae9adf89a5ea
|
|
| MD5 |
a05216f118714774eac4d30c5c2a45a2
|
|
| BLAKE2b-256 |
e9416f49aa7a71a960eabc50d8950be1a6315d6f227ab77570444722c5132312
|
Provenance
The following attestation bundles were made for quantava-0.2.0.tar.gz:
Publisher:
release.yml on Quantava/quantava-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quantava-0.2.0.tar.gz -
Subject digest:
659833ef0dccf61ded00e6416ddb45a41a4db5b8157a9d71144bae9adf89a5ea - Sigstore transparency entry: 1749496443
- Sigstore integration time:
-
Permalink:
Quantava/quantava-python-sdk@c32ac37f5cc6b767f9d1a9f9dd3dfdb7968d0201 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Quantava
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c32ac37f5cc6b767f9d1a9f9dd3dfdb7968d0201 -
Trigger Event:
push
-
Statement type:
File details
Details for the file quantava-0.2.0-py3-none-any.whl.
File metadata
- Download URL: quantava-0.2.0-py3-none-any.whl
- Upload date:
- Size: 48.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f7bf05ac8858503bc938afc8a7823b6a7772fcb6033400dce2c904c007dfb62
|
|
| MD5 |
60d175945e8ddefc6537a37ec4a6e8f7
|
|
| BLAKE2b-256 |
c3ed042f5dfd2429963dd30027f7b6523d1e93bdcd2da59492faa25d60df5de5
|
Provenance
The following attestation bundles were made for quantava-0.2.0-py3-none-any.whl:
Publisher:
release.yml on Quantava/quantava-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quantava-0.2.0-py3-none-any.whl -
Subject digest:
7f7bf05ac8858503bc938afc8a7823b6a7772fcb6033400dce2c904c007dfb62 - Sigstore transparency entry: 1749496574
- Sigstore integration time:
-
Permalink:
Quantava/quantava-python-sdk@c32ac37f5cc6b767f9d1a9f9dd3dfdb7968d0201 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Quantava
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c32ac37f5cc6b767f9d1a9f9dd3dfdb7968d0201 -
Trigger Event:
push
-
Statement type: