QuantumBPM Python SDK — DMN evaluation, BPMN orchestration, and external job workers.
Project description
QuantumBPM Python SDK
Official Python SDK for the QuantumBPM platform — DMN evaluation, BPMN process orchestration, and external job workers.
Installation
pip install quantumbpm-sdk
Python 3.10+. Async-first; built on asyncio.
What's in the box
| Module | Purpose |
|---|---|
quantumbpm.QuantumBPM |
Top-level client exposing .dmn, .bpmn, plus new_worker(...) |
quantumbpm.auth |
TokenProvider, ZitadelTokenProvider, StaticTokenProvider |
quantumbpm.dmn |
DMN evaluation: stored definitions, ad-hoc XML, batch |
quantumbpm.bpmn |
BPMN resources, instances, messaging, user tasks, processes |
quantumbpm.workers |
External job worker runtime — long-poll, lock heartbeat, dispatch |
quantumbpm.variables |
Vars wrapper with typed accessors and FEEL-context conversion |
quantumbpm.api[_client] |
OpenAPI-generated client. Reachable via client.raw, never hand-edited |
Quick start
import asyncio
from quantumbpm import QuantumBPM, Vars, ZitadelTokenProvider
async def main():
provider = ZitadelTokenProvider(
"./service-account.json", # Zitadel JSON Key file
"https://auth.quantumbpm.com", # issuer
"your-zitadel-project-id", # audience scope
)
async with QuantumBPM(
base_url="https://api.quantumbpm.com",
project_id="00000000-0000-0000-0000-000000000000",
token_provider=provider,
) as client:
result = await client.dmn.evaluate(
"loan-eligibility",
Vars().set("requestedAmt", 1000).set("creditScore", 720),
)
print(result)
asyncio.run(main())
The async context manager (async with) acquires a fresh bearer token on entry. Skipping the context manager and calling methods directly works too — the SDK refreshes tokens on demand.
Authentication
The TokenProvider Protocol returns a bearer token on each request. Two implementations ship out of the box.
Zitadel service account
from quantumbpm import ZitadelTokenProvider
provider = ZitadelTokenProvider(
"./service-account.json", # path to JSON Key file
"https://auth.quantumbpm.com", # issuer URL
"your-zitadel-project-id", # adds the audience scope
ssl_ca_cert="/path/to/ca.crt", # optional, for self-signed CAs
)
The provider caches tokens in-memory until shortly before expiry.
Static bearer token
For Enterprise deployments that issue long-lived API keys, or in tests where a token is acquired out of band:
from quantumbpm import StaticTokenProvider
provider = StaticTokenProvider("eyJhbGciOi...")
Bring your own
Implement the Protocol:
from quantumbpm import TokenProvider
class MyProvider:
async def get_token(self) -> str:
return await fetch_my_token()
provider: TokenProvider = MyProvider()
DMN evaluation
The client.dmn sub-client offers four async methods.
Evaluate a stored definition
result = await client.dmn.evaluate(
"loan-eligibility",
Vars().set("requestedAmt", 5000).set("creditScore", 720),
)
Returns dict[str, EvaluationResult] keyed by decision name. Each result has value, hit_rules, error, and type.
Pin a version, restrict the evaluated decisions, or attach decision services:
result = await client.dmn.evaluate(
"loan-eligibility",
vars,
version=3,
decisions=["eligibility", "rate"],
)
Evaluate by platform UUID
When you already hold a database-version pointer:
result = await client.dmn.evaluate_by_id(definition_uuid, vars)
Ad-hoc XML evaluation
For "evaluate while editing" flows that don't store the XML:
result = await client.dmn.evaluate_design(
dmn_xml,
vars,
additional_xmls=[imported_xml1, imported_xml2],
decisions=["eligibility"],
)
Batch ad-hoc evaluation
rows = [
Vars().set("requestedAmt", 1000),
Vars().set("requestedAmt", 5000),
Vars().set("requestedAmt", 25000),
]
batch = await client.dmn.evaluate_design_batch(dmn_xml, rows)
BPMN processes
client.bpmn covers the full BPMN runtime surface.
Deploy and start
draft = await client.bpmn.create_resource("loan-process", bpmn_xml)
await client.bpmn.deploy_resource(draft.id)
# Re-fetch to get the populated process-definition list.
deployed = await client.bpmn.get_resource(draft.id)
process_def = deployed.processes[0]
workflow_id = await client.bpmn.start_instance(
process_def.id,
Vars().set("applicantID", "u-123").set("requestedAmt", 25000),
)
Inspect runtime state
state = await client.bpmn.get_instance(workflow_id)
print(state.status, state.active_scopes)
vars = await client.bpmn.get_instance_variables(workflow_id)
children = await client.bpmn.get_instance_children(workflow_id)
Send messages and signals
await client.bpmn.publish_message(
"loan-approved",
Vars().set("approvedAmt", 24000),
correlation_keys={"applicantID": "u-123"},
ttl="PT5M",
)
await client.bpmn.publish_signal("system-maintenance")
User tasks
page = await client.bpmn.list_user_tasks(
assignee="alice@example.com",
status="CREATED",
)
await client.bpmn.complete_user_task(execution_key, Vars().set("approved", True))
# Or fail with a BPMN error code (matches boundary error events):
await client.bpmn.throw_user_task_error(execution_key, "REVIEW_REJECTED")
External job workers
Workers handle service tasks asynchronously. Register a handler per task type with a decorator, then call run. The runtime owns long-polling, lock heartbeats, dispatch, and outcome mapping.
Minimal worker
import asyncio
from quantumbpm import QuantumBPM, Vars, BpmnError
from quantumbpm.workers import Job
async def main():
async with QuantumBPM(...) as client:
worker = client.new_worker(client_id="billing-svc")
stop = asyncio.Event()
@worker.handler("send-email")
async def handle(job: Job) -> Vars:
recipient = job.vars.lookup("recipient")
subject = job.vars.lookup("subject")
await emailer.send(recipient, subject)
return Vars().set("messageID", "msg-123") # → Complete
await worker.run(stop) # blocks until stop is set
asyncio.run(main())
run(stop) resolves when the asyncio.Event is set, after in-flight handlers settle.
Concurrency, polling, and locks
@worker.handler(
"send-email",
max_jobs=10, # up to 10 in flight per task type
poll_timeout="45s", # long-poll wait
lock_duration="2m", # exclusive lock per job
)
async def handle(job: Job) -> Vars:
...
Concurrency is per task type. Different task types run independently. The runtime auto-renews the lock at half the lock-duration interval while the handler runs.
Throwing typed BPMN errors
Raise a BpmnError to fail the job with a code that boundary error events on the originating service task can catch:
@worker.handler("charge-card")
async def handle(job: Job) -> Vars:
try:
tx_id = await charge(job.vars.to_dict())
return Vars().set("transactionID", tx_id)
except InsufficientFundsError:
raise BpmnError("INSUFFICIENT_FUNDS", Vars().set("availableBalance", 12.0))
Any other exception is reported as WORKER_ERROR, which the server treats as a retryable failure that decrements the job's retry budget.
Typed handlers (Pydantic)
Type-annotate the Job parameter with a Pydantic model — the runtime validates the job's input variables before invoking the handler. The decoded value lands in job.typed.
from pydantic import BaseModel
from quantumbpm.workers import Job
class EmailJob(BaseModel):
recipient: str
subject: str
@worker.handler("send-email")
async def handle(job: Job[EmailJob]) -> Vars:
await emailer.send(job.typed.recipient, job.typed.subject)
return Vars().set("messageID", "msg-123")
Decode failures become WORKER_ERROR automatically, with the validation message in the variables.
Variables
Vars is a thin wrapper around dict[str, Any] shared by DMN, BPMN, and workers.
Construction
v = Vars().set("amount", 100).set("name", "Alice")
v = Vars.from_dict({"amount": 100, "name": "Alice"})
Typed access
amount = v.get("amount", float)
flag = v.get("approved", bool)
class Loan(BaseModel):
requestedAmt: float
approved: bool
loan = v.as_type(Loan)
Vars.get(name, type_) and Vars.as_type(type_) accept Pydantic models, dataclasses, and primitives — Pydantic's TypeAdapter does the validation.
Escape hatch
The client.raw property exposes the underlying generated ApiClient for endpoints not yet wrapped (instance migration, modification, ad-hoc triggers, batch job complete/error, etc.):
from quantumbpm.api.bpmn_api import BpmnApi
api = BpmnApi(client.raw)
result = api.migrate_bpmn_instance(client.project_id, workflow_id, body)
License
MIT License — see LICENSE for details.
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 quantumbpm_sdk-0.12.0.tar.gz.
File metadata
- Download URL: quantumbpm_sdk-0.12.0.tar.gz
- Upload date:
- Size: 93.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b78f4ffb493ab1a26c55cdf9cecc947308d07425f214fa6db2e28c005f2e66cc
|
|
| MD5 |
3769db9fafd855d6602e299e04a2d6e8
|
|
| BLAKE2b-256 |
56023ef94c98e3dd2e810d67921acc4e0977425fb6e816a3563f98a51c8751ff
|
Provenance
The following attestation bundles were made for quantumbpm_sdk-0.12.0.tar.gz:
Publisher:
release.yml on QuantumBPM/quantum-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quantumbpm_sdk-0.12.0.tar.gz -
Subject digest:
b78f4ffb493ab1a26c55cdf9cecc947308d07425f214fa6db2e28c005f2e66cc - Sigstore transparency entry: 1624597432
- Sigstore integration time:
-
Permalink:
QuantumBPM/quantum-python-sdk@9067f093aff73e92d48736bb83ddb324412d90d4 -
Branch / Tag:
refs/tags/v0.12.0 - Owner: https://github.com/QuantumBPM
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9067f093aff73e92d48736bb83ddb324412d90d4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file quantumbpm_sdk-0.12.0-py3-none-any.whl.
File metadata
- Download URL: quantumbpm_sdk-0.12.0-py3-none-any.whl
- Upload date:
- Size: 195.5 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 |
2b2f9daeeeee0d0946940991e030cbd5c6ff6f3ee6cdf41cf6a52e2b10eaf7f5
|
|
| MD5 |
6c6ab22980520728708f4432579dc318
|
|
| BLAKE2b-256 |
05fb71c582969d8f4b00272027022f2a6edd8f542e776d7d806b584ec5d907d5
|
Provenance
The following attestation bundles were made for quantumbpm_sdk-0.12.0-py3-none-any.whl:
Publisher:
release.yml on QuantumBPM/quantum-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quantumbpm_sdk-0.12.0-py3-none-any.whl -
Subject digest:
2b2f9daeeeee0d0946940991e030cbd5c6ff6f3ee6cdf41cf6a52e2b10eaf7f5 - Sigstore transparency entry: 1624597445
- Sigstore integration time:
-
Permalink:
QuantumBPM/quantum-python-sdk@9067f093aff73e92d48736bb83ddb324412d90d4 -
Branch / Tag:
refs/tags/v0.12.0 - Owner: https://github.com/QuantumBPM
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9067f093aff73e92d48736bb83ddb324412d90d4 -
Trigger Event:
push
-
Statement type: