Skip to main content

dagflows

Python SDK for authoring and running Dagflows workflows.

Installation

pip install dagflows

Requires Python 3.11+.

To enable the optional async HTTP client backend:

pip install dagflows[httpx]

Quickstart

Define a workflow and its node functions in a module:

# app/workflow.py
from dagflows import Workflow

wf = Workflow("order_pipeline", max_concurrent_nodes=4)


@wf.node()
def fetch_orders(ctx, inputs):
    return {"orders": [{"id": 1, "amount": 100}, {"id": 2, "amount": 250}]}


@wf.node(depends=[fetch_orders])
def calculate_totals(ctx, inputs):
    orders = inputs["fetch_orders"].value()["orders"]
    total = sum(order["amount"] for order in orders)
    return {"total": total}

Handler Signatures

A handler declares what it needs, so a node that only reads its parents does not carry an unused ctx. Ask for arguments by name, in any order:

# Both
@wf.node()
def step_a(ctx, inputs):
    ...

# Inputs only
@wf.node(depends=[step_a])
def step_b(inputs):
    ...

# Context only
@wf.node()
def step_c(ctx):
    ...

# Neither
@wf.node()
def step_d():
    return {"status": "ready"}

# Async works identically
@wf.node(depends=[step_a])
async def step_async(ctx, inputs):
    async for item in inputs["step_a"]:
        ...
    return {"done": True}

Annotating

Annotate for editor completion, which the SDK ships py.typed to support:

from dagflows import Ctx, Inputs


@wf.node()
def step(ctx: Ctx, inputs: Inputs):
    inputs.one().value()      # completion on both

An annotation also frees the name, so call the parameters whatever suits you:

@wf.node()
def step(payload: Inputs, context: Ctx):
    ...

A parameter that is neither named nor annotated is refused, naming the fix:

transform: cannot tell what to pass to 'data'.
Name it 'ctx' or 'inputs', or annotate it:

    def transform(data: Inputs): ...

That refusal happens while the manifest is emitted, so a bad signature fails the build rather than the first run.

Node Configuration

Resource Limits and Retries

Configure execution limits and retry policies on @wf.node():

from dagflows import ExecutionConfig, RetryConfig, Workflow

wf = Workflow("data_pipeline")


@wf.node(
    execution=ExecutionConfig(timeout=300, memory_limit_mb=512),
    retry=RetryConfig(max_attempts=3, initial_backoff_ms=1000),
)
def extract_data(ctx, inputs):
    ...

Cross-Project Dependencies

To depend on a node from another project or workflow, use wf.external_node:

@wf.node(depends=[fetch_orders, wf.external_node("inventory_check")])
def fulfill_order(ctx, inputs):
    ...

Standalone Node Scripts (Optional)

In addition to defining nodes within a workflow module, you can also write standalone script files using dagflows.run:

# app/nodes/custom_task.py
import dagflows


def handler(ctx, inputs):
    data = inputs.one().value()
    return {"processed": True, "count": len(data)}


if __name__ == "__main__":
    dagflows.run(handler)

Working with Inputs

Inputs are accessed through input handles:

upstream = inputs["fetch_orders"]

# Retrieve complete value, refused if it exceeds the node's memory limit
data = upstream.value()

# Iterate without holding it all (sync and async iteration both work)
for record in upstream:
    process_record(record)

# Raw chunks for opaque content: a generator, not a bytes object
for chunk in upstream.bytes():
    sink.write(chunk)

Iteration yields one record at a time for row oriented payloads, which is what lets a node read more than it can hold. A JSON input has no records, so it yields the whole document as a single item.

content type for x in handle yields
application/x-ndjson, text/csv one row at a time
application/json the whole document, once

Iteration re-opens the source each pass, so looping twice costs a second read rather than silently yielding nothing the second time.

If a node has exactly one parent dependency, use inputs.one():

single_input = inputs.one().value()

Producing Outputs

Return a Python dictionary/value directly, or use Result for explicit routing and formatting:

from dagflows import ContentType, Result

# Direct value return
return {"count": 42}

# Route downstream execution to a specific branch
return Result(output={"status": "approved"}, next="process_payment")

# Halt execution of this branch
return Result(output={}, stop=True)

# Explicit content type specification
return Result(output=stream_generator(), content_type=ContentType.NDJSON)

Error Handling

Raise Fail to signal structured execution errors with retry instructions:

from dagflows import EXECUTION, Fail

raise Fail("Payment gateway unavailable", category=EXECUTION, retry_after=30)

Available error categories:

  • EXECUTION
  • INFRASTRUCTURE
  • TIMEOUT
  • PERMANENT

Command Line Interface

The SDK provides CLI commands invoked via python -m dagflows:

Manifest Management

# Generate manifest file
python -m dagflows build manifest app.workflow -o dagflows-manifest.json

# Check if an existing manifest is up to date
python -m dagflows build manifest app.workflow --check

# Validate workflow definition without writing output
python -m dagflows build validate app.workflow

Local Development & Testing

dev run executes a node with no VM, no platform and no network. It takes a script path, so it applies to standalone node scripts:

python -m dagflows dev run app/nodes/custom_task.py --input fetch_orders=orders.json

dev fixture writes a starting input envelope, so nobody has to invent one. It takes either form:

# a standalone script
python -m dagflows dev fixture app/nodes/custom_task.py -o fixture.json

# a node declared with @wf.node
python -m dagflows dev fixture app.workflow:calculate_totals --input fetch_orders=orders.json -o m.json

It prints the command that runs the node against what it wrote, which for a decorated node goes through the interpreter because a module:function entrypoint is not a file:

DAGFLOWS_INPUT=m.json DAGFLOWS_OUTPUT=out.json python -m dagflows invoke --node calculate_totals

That is the local loop for decorator-defined nodes, since dev run needs a file to execute.

dev run accepts several options worth knowing:

--input users=rows.ndjson     a file, content type inferred from the suffix
--input users='{"n": 1}'      inline json
--memory-limit-mb 512         what the node believes it has
--inline-max-bytes 262144     when an output would offload
--keep-fixture <path>         write the envelope instead of discarding it

All CLI commands support --json for machine-readable output. Exit codes are 0 success, 1 the operation failed, 2 the command was wrong.

License

Apache-2.0

Download files

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

Source Distribution

dagflows-0.2.1.tar.gz (63.1 kB view details)

Uploaded Source

Built Distribution

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

dagflows-0.2.1-py3-none-any.whl (42.3 kB view details)

Uploaded Python 3

File details

Details for the file dagflows-0.2.1.tar.gz.

File metadata

  • Download URL: dagflows-0.2.1.tar.gz
  • Upload date:
  • Size: 63.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dagflows-0.2.1.tar.gz
Algorithm Hash digest
SHA256 811d95094aeb01599abe656f92ce34c7b8a875e2991ea34ed3d47f307b32f2a6
MD5 022b8d3e6eae219ed0620ac2cafc7787
BLAKE2b-256 3f842e9f5949b5c6859a011cfe9234f671324a57fc7b0efdbeff8d489cb6d59b

See more details on using hashes here.

Provenance

The following attestation bundles were made for dagflows-0.2.1.tar.gz:

Publisher: release.yml on dagflows/sdk-python

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

File details

Details for the file dagflows-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: dagflows-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 42.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dagflows-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5e7ef3a74f7a7d1f05de5ad7e13c628147d205244f56f0bb8a51696b4dc016fd
MD5 edffadfee8e94ce0f0f62621da96ea86
BLAKE2b-256 5ced68f7094e90d97a25b932ed5ef79d42075530d2c9e4a06a6af9bca052b7a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for dagflows-0.2.1-py3-none-any.whl:

Publisher: release.yml on dagflows/sdk-python

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

Release history Release notifications | RSS feed

0.5.0

2 files

0.3.0

2 files

0.2.3

2 files

0.2.2

2 files

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page