Skip to content

WaitSensor - time_to_wait templated - #70480

Merged
potiuk merged 1 commit into
apache:mainfrom
raphaelauv:feat/WaitSensor_templated_time_to_wait
Jul 31, 2026
Merged

WaitSensor - time_to_wait templated#70480
potiuk merged 1 commit into
apache:mainfrom
raphaelauv:feat/WaitSensor_templated_time_to_wait

Conversation

@raphaelauv

Copy link
Copy Markdown
Contributor

time_to_wait should be templated so we can do

from airflow.sdk import DAG, Param
from airflow.providers.standard.sensors.time_delta import WaitSensor
with DAG(
        dag_id="my_dag",
        start_date=datetime(2024, 1, 1),
        schedule=None,
        catchup=False,
        params={
            "duration_minutes": Param(
                default=30,
                type="integer",
                minimum=1,
                description="Duration in minutes to wait.",
            )
        },
):

    WaitSensor(
        task_id="wait_for_duration",
        time_to_wait="{{ params.duration_minutes }}",
        deferrable=True
    )

@raphaelauv
raphaelauv force-pushed the feat/WaitSensor_templated_time_to_wait branch from 8d1d3a8 to 5a76146 Compare July 27, 2026 07:44
@potiuk potiuk added the ready for maintainer review Set after triaging when all criteria pass. label Jul 28, 2026

@potiuk potiuk 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 — and this one lands on the right side of a distinction that's been catching people out.

Making time_to_wait templated requires moving the int -> timedelta conversion out of __init__, because at construction time the value may still be "{{ ... }}". That's a value transformation, so deferring it to execute is correct — unlike a provision check ("was this argument passed?"), which per #70296 must stay in the constructor. Worth saying explicitly since several PRs in that campaign have moved the wrong kind.

I checked the one thing that can quietly break when a class declares template_fields: BaseSensorOperator doesn't define any, and neither does TimeDeltaSensor in the same module, so this is purely additive — nothing inherited gets shadowed.

_resolve_time_to_wait handling timedelta passthrough and int(value) for both native ints and rendered strings is the right shape, and the parametrisation over timedelta(minutes=1), 1, and "{{ 1*2 }}" covers all three input forms that can now reach it.

One small thought, not blocking: test_wait_sensor_templating_error pins Python's raw message, invalid literal for int() with base 10: 'nothing'. That's accurate but it's CPython's wording rather than ours, so the test is coupled to something we don't control. Wrapping the conversion to raise something like ValueError(f"time_to_wait must be a number of minutes or a timedelta, got {value!r}") would give users a better message and give the test something stable to assert.


Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting

@potiuk
potiuk merged commit 3abf9ca into apache:main Jul 31, 2026
155 checks passed
@raphaelauv
raphaelauv deleted the feat/WaitSensor_templated_time_to_wait branch August 3, 2026 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants