Skip to content

Implement Python task handler and support it in YAML Dags - #75405

Open
uranusjr wants to merge 5 commits into
apache:mainfrom
astronomer:python-task-handler
Open

uranusjr wants to merge 5 commits into
apache:mainfrom
astronomer:python-task-handler

Conversation

@uranusjr

@uranusjr uranusjr commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

This implements a Python equivalent to Language SDK’s ADR-0011 interface as a @task_handler(...) decorator function. The general design matches exactly to the ADR; a task handler is registered (with the decorator) under a dag_id, task_id key, and a coordinator is specified to find the handler.

This information is used twice, once at parse-time to do a best-effort signature validation (as specified in ADR-0011), and again on execution through the same AIP-108 interface that routes a Python stub to non-Python task handlers.

While the feature as it stands now solely serves the YAML Dag format, it also is not specific to it. We now have the Python interface to allow Dags in any language to create a stub to resolve into a Python function at runtime—although no Dag formats currently have such a stub interface (except Python, but you don’t need this to call Python from Python in the first place).

Close #75273.

@uranusjr uranusjr added this to the Airflow 3.5.0 milestone Oct 22, 2026
@uranusjr uranusjr self-assigned this Oct 22, 2026
@uranusjr uranusjr added the area:coordinator Coordinator: The interface to spawn Lang-SDK subprocesses label Oct 22, 2026
@uranusjr
uranusjr requested a review from kaxil October 22, 2026 14:45
Comment thread task-sdk/src/airflow/sdk/execution_time/task_runner.py Outdated
Comment thread task-sdk/src/airflow/sdk/execution_time/task_runner.py Outdated
Comment thread task-sdk/src/airflow/sdk/execution_time/task_runner.py Outdated
Comment thread task-sdk/src/airflow/sdk/execution_time/task_runner.py Outdated
Comment thread task-sdk/src/airflow/sdk/task_handlers/loader.py Outdated
Comment thread task-sdk/docs/task-handler.rst
assert getattr(result.dags[0].get_task("t"), "is_stub", False) is True


def test_matching_arguments_pass(mock_bundle, monkeypatch):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every declaration in this file has a single required=True param, so dropping if p.required in the builder keeps all five tests green. A case with TaskHandlerParam(name="limit", required=False) left out of run: would pin it. _patch_declaration's for_queue=lambda queue: coordinator ignores the queue, so routing by the task's queue: isn't tested either, and test_none_declaration_skips covers the same branch as test_no_declaration_available_skips_and_builds.

Comment thread task-sdk/tests/task_sdk/execution_time/test_run_task_handler.py Outdated
Comment thread task-sdk/tests/task_sdk/task_handlers/test_loader.py Outdated
Comment thread task-sdk/tests/task_sdk/task_handlers/test_task_handlers.py Outdated

@jason810496 jason810496 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the filling up the gap.

Comment thread airflow-core/docs/authoring-and-scheduling/yaml-dags.rst Outdated
Comment thread task-sdk/docs/task-handler.rst
Comment thread task-sdk/src/airflow/sdk/execution_time/task_runner.py Outdated
Comment thread task-sdk/src/airflow/sdk/task_handlers/loader.py Outdated
if missing := sorted({p.name for p in declaration.params if p.required} - run_names):
yield f"task {task.id_!r}: missing required handler argument(s) {missing}"
if unknown := sorted(run_names - {p.name for p in declaration.params}):
yield f"task {task.id_!r}: run argument(s) {unknown} are not parameters of its task handler"

@jason810496 jason810496 Oct 23, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to validate against the type like https://github.com/apache/airflow/pull/74067/changes#diff-a62ed98ec4693a9a9f43c7807c68805f64c92e233f808ce26121dcb70d03b81cR184 ?

e.g. reject a int literal being binded to a argument in list type

Comment thread task-sdk/src/airflow/sdk/task_handlers/binding.py Outdated
This is the Python equivalent to the Language SDK ADR-0007 interface.
The new interface allows a Dag author to write a Dag in YAML (other
languages will also automatically work as long as they implement the
stub interface), and wire up a PythonCoordinator in the configuration
plus the correct queue mapping to have it execute a Python function at
runtime.
This implements the Language SDK ADR-0011 interface between Python task
handlers and the YAML Dag parser. This allows the parser to use the
interface to validate 'run:' arguments against a matched task handler if
it exists.

As specified in ADR-0011, a missing task handler at parse-time does not
fail parsing; the error is only surfaced at execution time.
@uranusjr
uranusjr force-pushed the python-task-handler branch from 872aa73 to 3fe883e Compare October 26, 2026 20:09
@uranusjr
uranusjr force-pushed the python-task-handler branch from ccf4f1f to 4055abe Compare October 26, 2026 20:24

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:coordinator Coordinator: The interface to spawn Lang-SDK subprocesses area:task-sdk kind:documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Python task_handler decorator for YAML Dag ‘run’ tasks

3 participants