From 835e82e00aa714cdf9df212f5bde53fa79877ffa Mon Sep 17 00:00:00 2001 From: Adam <111773160+Pebble32@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:21:02 +0000 Subject: [PATCH 1/4] Make cron timetables hashable Signed-off-by: Adam <111773160+Pebble32@users.noreply.github.com> --- airflow-core/src/airflow/timetables/_cron.py | 2 +- .../tests/unit/timetables/test_trigger_timetable.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/airflow-core/src/airflow/timetables/_cron.py b/airflow-core/src/airflow/timetables/_cron.py index ed0b3c76bb786..245cc3fbc3953 100644 --- a/airflow-core/src/airflow/timetables/_cron.py +++ b/airflow-core/src/airflow/timetables/_cron.py @@ -131,7 +131,7 @@ def __eq__(self, other: object) -> bool: return self._expression == other._expression and self._timezone == other._timezone def __hash__(self): - return hash((self._expression, self._timezone)) + return hash((self._expression, str(self._timezone))) @property def summary(self) -> str: diff --git a/airflow-core/tests/unit/timetables/test_trigger_timetable.py b/airflow-core/tests/unit/timetables/test_trigger_timetable.py index f4718f8d04bb9..8e448ed325fd2 100644 --- a/airflow-core/tests/unit/timetables/test_trigger_timetable.py +++ b/airflow-core/tests/unit/timetables/test_trigger_timetable.py @@ -1196,3 +1196,11 @@ def test_run_immediately_does_not_pick_future_run(get_info: typing.Callable[[], assert info is not None assert info.run_after <= pendulum.DateTime(2024, 11, 3, 5, 30, tzinfo=utc) assert info.run_after == pendulum.DateTime(2024, 11, 2, 5, tzinfo=utc) + + +def test_cron_timetables_are_hashable(): + """pendulum ``Timezone`` is unhashable, so hashing the timezone object made ``hash()`` raise.""" + timetable = CronTriggerTimetable("0 0 * * *", timezone="UTC") + same = CronTriggerTimetable("0 0 * * *", timezone="UTC") + assert timetable == same + assert hash(timetable) == hash(same) From 8f5abf5fa7d29f1704e7d5d6f9037a840f08cbc4 Mon Sep 17 00:00:00 2001 From: Adam <111773160+Pebble32@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:21:10 +0000 Subject: [PATCH 2/4] Add newsfragment Signed-off-by: Adam <111773160+Pebble32@users.noreply.github.com> --- airflow-core/newsfragments/73859.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 airflow-core/newsfragments/73859.bugfix.rst diff --git a/airflow-core/newsfragments/73859.bugfix.rst b/airflow-core/newsfragments/73859.bugfix.rst new file mode 100644 index 0000000000000..8186b3010c3c8 --- /dev/null +++ b/airflow-core/newsfragments/73859.bugfix.rst @@ -0,0 +1 @@ +Fix ``hash()`` raising ``TypeError: unhashable type: 'Timezone'`` on cron-based timetables. From 56136828cb36702f7e8f843d82cd1e787e7e2a23 Mon Sep 17 00:00:00 2001 From: Adam Postek <111773160+Pebble32@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:52:41 +0000 Subject: [PATCH 3/4] Update airflow-core/tests/unit/timetables/test_trigger_timetable.py Co-authored-by: Ash Berlin-Taylor --- airflow-core/tests/unit/timetables/test_trigger_timetable.py | 1 - 1 file changed, 1 deletion(-) diff --git a/airflow-core/tests/unit/timetables/test_trigger_timetable.py b/airflow-core/tests/unit/timetables/test_trigger_timetable.py index 8e448ed325fd2..02a58323e14ea 100644 --- a/airflow-core/tests/unit/timetables/test_trigger_timetable.py +++ b/airflow-core/tests/unit/timetables/test_trigger_timetable.py @@ -1199,7 +1199,6 @@ def test_run_immediately_does_not_pick_future_run(get_info: typing.Callable[[], def test_cron_timetables_are_hashable(): - """pendulum ``Timezone`` is unhashable, so hashing the timezone object made ``hash()`` raise.""" timetable = CronTriggerTimetable("0 0 * * *", timezone="UTC") same = CronTriggerTimetable("0 0 * * *", timezone="UTC") assert timetable == same From 22ff344b9f193afa29b676688dc4da98dbf8a5c3 Mon Sep 17 00:00:00 2001 From: Adam <111773160+Pebble32@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:58:48 +0000 Subject: [PATCH 4/4] Remove newsfragment Signed-off-by: Adam <111773160+Pebble32@users.noreply.github.com> --- airflow-core/newsfragments/73859.bugfix.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 airflow-core/newsfragments/73859.bugfix.rst diff --git a/airflow-core/newsfragments/73859.bugfix.rst b/airflow-core/newsfragments/73859.bugfix.rst deleted file mode 100644 index 8186b3010c3c8..0000000000000 --- a/airflow-core/newsfragments/73859.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``hash()`` raising ``TypeError: unhashable type: 'Timezone'`` on cron-based timetables.