I like the new decorator.

One small comment on short-circuiting itself (not your proposal specifically):

I never liked ShortCircuitOperator because it is semantically the other way 
around—short-circuiting means the dag would take a shortcut to the end, so 
*True* should make short-circuit happen, instead of continuing. This is 
_marginally_ acceptable with ShortCircuitOperator, but a decorator makes things 
even more confusing.

I would prefer the new decorator be called e.g. short_circuit_if_false instead 
to make more sense.

TP



> On 17 Mar 2026, at 18:03, Dev-iL <[email protected]> wrote:
> 
> |Hello everyone,|
> ||
> |I'd like to initiate a vote on a new DAG authorship best practice.|
> ||
> |## Proposal|
> ||
> |When a `@task.branch` (or `BranchPythonOperator`) function has **at least 
> two `return` statements**, and **exactly one of them returns a non-empty 
> list**, the function is effectively acting as a binary gate — either run a 
> specific set of downstream tasks, or skip them all.|
> ||
> |In that case, **`@task.short_circuit`** (`ShortCircuitOperator`) is a 
> simpler and more readable alternative: it expresses the same intent by 
> returning `True`/`False`, rather than requiring the caller to reason about 
> list-vs-empty-list semantics.|
> ||
> |### Before|
> ||
> |```python|
> |from airflow.decorators import task|
> ||
> |@task.branch|
> |def check_condition():|
> |if some_condition:|
> |return ["downstream_task"]|
> |return []|
> |```|
> ||
> |### After|
> ||
> |```python|
> |from airflow.decorators import task|
> ||
> |@task.short_circuit|
> |def check_condition():|
> |return some_condition|
> |```|
> ||
> |The same principle applies to the classic operator form.|
> ||
> |## Rationale|
> ||
> |- **Clarity:** `@task.short_circuit` makes intent immediately obvious — the 
> task either proceeds or it doesn't. Readers no longer need to inspect return 
> values to determine that the branch is binary.|
> |- **Less boilerplate:** Eliminates the need to wrap a boolean condition in a 
> single-element list.|
> |- **Correct semantics:** `@task.branch` with a single non-empty return is a 
> degenerate case of branching; `@task.short_circuit` is the idiomatic tool for 
> this pattern.|
> |- **Consistency:** The rule applies equally to the TaskFlow API 
> (`@task.branch`) and the traditional operator API (`BranchPythonOperator`), 
> covering both authorship styles uniformly.|
> ||
> |## Cases NOT affected by this proposal|
> ||
> |This best practice only applies when the function structure is unambiguously 
> binary:|
> ||
> |- Functions with **multiple non-empty list returns** are genuine branching 
> logic — no change suggested.|
> |- Functions with **only a single return** — no change suggested.|
> |- Functions returning **non-list values** (strings, `None`, etc.) — no 
> change suggested.|
> ||
> |## Call for Consensus|
> ||
> |Please let me know if you have concerns, questions, or support.|
> ||
> |Thank you,|
> |Dev-iL|
> ||
> |---|
> ||
> |## See Also|
> ||
> |1. [apache/airflow#43176 
> (comment)](https://github.com/apache/airflow/issues/43176#issuecomment-2667604469)
>  — original proposal in the static checks tracking issue|
> |2. [astral-sh/ruff#23579](https://github.com/astral-sh/ruff/pull/23579) — 
> Draft Ruff PR implementing (`task-branch-as-short-circuit`)|
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to