Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quantumbpm_sdk-0.12.0.tar.gz (93.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quantumbpm_sdk-0.12.0-py3-none-any.whl (195.5 kB view details)

Uploaded Python 3

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

Hashes for quantumbpm_sdk-0.12.0.tar.gz
Algorithm Hash digest
SHA256 b78f4ffb493ab1a26c55cdf9cecc947308d07425f214fa6db2e28c005f2e66cc
MD5 3769db9fafd855d6602e299e04a2d6e8
BLAKE2b-256 56023ef94c98e3dd2e810d67921acc4e0977425fb6e816a3563f98a51c8751ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for quantumbpm_sdk-0.12.0.tar.gz:

Publisher: release.yml on QuantumBPM/quantum-python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for quantumbpm_sdk-0.12.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2b2f9daeeeee0d0946940991e030cbd5c6ff6f3ee6cdf41cf6a52e2b10eaf7f5
MD5 6c6ab22980520728708f4432579dc318
BLAKE2b-256 05fb71c582969d8f4b00272027022f2a6edd8f542e776d7d806b584ec5d907d5

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page