Result¶
Result is the dataclass returned by wf.run(), wf.run_async(), and
wf.deploy_and_run(). It captures everything you need to know about a
single workflow execution:
from athena_sdk import Workflow
wf = Workflow("demo")
wf.python_transform(
"echo",
code="def transform(row):\n return {'ok': True}\n",
)
result = wf.run()
print(result.ok) # True / False
print(result.status) # "completed" | "failed"
print(result.duration) # wall-clock seconds
print(result.execution_id) # backend run id (None for pure-local)
print(result.node_results["echo"].output)
Truthy shortcut¶
Result.__bool__ is True when the workflow completed successfully
and False otherwise, so you can treat the result like a status
sentinel:
result.ok is the same check spelled out explicitly. Use whichever
reads better at the call site.
Per-node outcomes¶
Each node that ran is in result.node_results, keyed by node name:
@dataclass
class NodeResult:
name: str
status: str # "completed" | "failed" | "skipped"
duration: float | None # seconds, may be None for skipped nodes
output: Any # whatever the node returned
error: str | None # populated when status == "failed"
A typical post-mortem loop:
result = wf.run()
for name, nr in result.node_results.items():
if nr.status == "failed":
print(f"✗ {name} ({nr.duration:.2f}s): {nr.error}")
elif nr.status == "skipped":
print(f"– {name} skipped")
else:
print(f"✓ {name} ({nr.duration:.2f}s)")
Skipped nodes appear when an upstream if_ / switch routed control
away from them, or when wf.deploy_and_run() is invoked with
partial=True against a hosted backend.
Outputs¶
NodeResult.output is whatever the node produced — a list of dicts
from a Postgres SELECT, a single dict from a python_transform, an
S3 object key from an S3 write, etc. The shape is documented per-node
in the API reference. For typed access
across nodes inside a workflow, use expressions:
from athena_sdk import expr
wf.api(
"notify",
url="https://hooks.slack.com/...",
body={"text": expr.node("Loader").get("rows").len()},
)
Logs¶
result.logs is a list of human-readable log lines emitted during the
run. The bundled engine captures stdout/stderr from python_transform
nodes plus its own diagnostic messages here. For larger or
streaming use cases (long-running workflows on a hosted backend), see
AthenaClient.executions.logs_stream().
Errors¶
When status == "failed", result.error is a high-level summary
string and the failing node will have its own error populated. For
typed exception handling on the build side (before you ever call
run()), see Errors:
| Exception | Raised when |
|---|---|
WorkflowBuildError |
A typed builder rejects an invalid configuration at build time |
ValidationError |
A hosted backend returns 422 from client.workflows.create() |
RemoteAPIError |
Any non-2xx from a hosted backend (network, auth, server) |
AthenaSDKError |
Catch-all base for all SDK exceptions |
Local execution failures surface through the Result object, not
exceptions — wf.run() only raises if something failed catastrophically
before any node could run (e.g. the engine couldn't connect to its
state Postgres).