Run a small Python snippet with a pinned Python runtime from a Dagu workflow.
This action is useful for lightweight data transforms, release metadata generation, API glue code, and other cases where a full checked-in Python script would be heavier than the logic itself.
steps:
- id: compute
action: python-script@v1
with:
input:
version: "1.2.3"
services: ["api", "worker"]
requirements:
- packaging==25.0
script: |
from packaging.version import Version
print("preparing release", input["version"])
return {
"major": Version(input["version"]).major,
"serviceCount": len(input["services"]),
"services": input["services"],
}
- id: print
depends: [compute]
run: echo "major version is ${compute.outputs.result.major}"The action owns its runtime dependency:
tools:
- astral-sh/uv@0.11.14Callers do not need to install Python or uv on every worker image. Dagu prepares the pinned uv tool for the action DAG on the worker that runs it, and uv prepares the requested Python runtime.
| Field | Required | Description |
|---|---|---|
script |
Yes | Python async function body. Use return to publish a result. await is supported. |
input |
No | JSON-compatible value available to the script as input. Defaults to None. |
requirements |
No | List of pip-compatible requirement specifiers installed with uv run --with. Defaults to an empty list. |
env |
No | Object of string environment variables to add to the script process. Also available as env. |
timeoutSeconds |
No | Timeout enforced by the wrapper for the user script process, including the inner uv run that prepares the requested Python version and requirements. Defaults to 30, max 300. |
pythonVersion |
No | Exact Python version for uv to run. Defaults to 3.13.9. |
The script runs as an async function body with these variables in scope:
input # value from with.input, or None
params # full action input object
env # os.environ plus with.env valuesBecause the script body is async, await works directly:
steps:
- id: inspect
action: python-script@v1
with:
script: |
import asyncio
import platform
await asyncio.sleep(0.1)
return {
"python": platform.python_version(),
"platform": platform.system(),
}| Field | Description |
|---|---|
ok |
true when the script completed successfully. |
result |
JSON-compatible value returned by the script. None becomes null. |
stdout |
Text written to stdout with print() or other stdout writes. |
stderr |
Text written to stderr by the script process. |
durationMs |
Wrapper-measured duration in milliseconds. This starts after Dagu has already prepared the uv tool and started the action wrapper. |
pythonVersion |
Python version used by the script process. |
error |
Error object with name, message, and stack when the script fails. |
Script stdout and stderr are captured for structured outputs and mirrored to the action step stderr so they remain visible in logs without corrupting the JSON stdout Dagu uses for outputs. Dagu's own tool preparation and the outer action bootstrap remain bounded by the action DAG step timeout.
Use requirements for small, pinned Python dependencies:
steps:
- id: parse
action: python-script@v1
with:
requirements:
- python-dateutil==2.9.0.post0
script: |
from dateutil.parser import isoparse
return {
"year": isoparse("2026-05-18T00:00:00Z").year,
}For private indexes or credentials, pass the relevant uv or pip environment variables through env, for example UV_INDEX, UV_DEFAULT_INDEX, or UV_INDEX_URL.
This action is not a sandbox. The script runs with the same permissions, filesystem access, network access, and secrets available to the Dagu worker process. Only run trusted Python.
dagu-action.yaml
workflow.yaml
scripts/
run-python-script.py