This is an automated email from the ASF dual-hosted git repository.
dabla pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 7839f4a2da0 Type the durable default of the common.compat
ResumableJobMixin stand-in as bool | None (#75271)
7839f4a2da0 is described below
commit 7839f4a2da09c3dba27f52ce23707fa919b0b6a7
Author: David Blain <[email protected]>
AuthorDate: Wed Oct 28 14:11:16 2026 +0100
Type the durable default of the common.compat ResumableJobMixin stand-in as
bool | None (#75271)
* Type the durable default of the common.compat ResumableJobMixin stand-in
as bool | None
Follow-up to #74673, addressing the post-merge review comment
(https://github.com/apache/airflow/pull/74673#pullrequestreview-5596067358).
The stand-in annotated `durable: bool` but defaulted it to an `object()`
sentinel that was typed `Any`
to keep mypy quiet. It now defaults to `None`, the value the operators
already use for "not set"
(they only forward `durable` when it is not `None`), so the annotation is
accurate and mypy keeps
checking the argument. No behaviour change: only an explicit
`durable=True/False` warns below 3.3.
* Test that an explicit durable=None does not warn in the ResumableJobMixin
stand-in
The no-warning test only covered durable left out, so a change back to
warning on an explicit
None would have passed. It now runs with durable left out and with
durable=None.
---
.../airflow/providers/common/compat/_resumable_job_mixin.py | 10 ++++------
.../tests/unit/common/compat/test__resumable_job_mixin.py | 5 +++--
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git
a/providers/common/compat/src/airflow/providers/common/compat/_resumable_job_mixin.py
b/providers/common/compat/src/airflow/providers/common/compat/_resumable_job_mixin.py
index aa2b9c2f4c3..d4b35ba0024 100644
---
a/providers/common/compat/src/airflow/providers/common/compat/_resumable_job_mixin.py
+++
b/providers/common/compat/src/airflow/providers/common/compat/_resumable_job_mixin.py
@@ -32,18 +32,16 @@ from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from airflow.sdk.definitions.context import Context
-# Tells "durable left at its default" apart from an explicit
durable=True/False, so only an explicit
-# value warns that it has no effect here.
-_DURABLE_UNSET: Any = object()
-
class ResumableJobMixin:
"""Airflow < 3.3 stand-in: no ``task_state_store`` to resume from, so
every try submits a new job."""
external_id_key: str = "remote_job_id"
- def __init__(self, *, durable: bool = _DURABLE_UNSET, **kwargs: Any) ->
None:
- if durable is not _DURABLE_UNSET:
+ def __init__(self, *, durable: bool | None = None, **kwargs: Any) -> None:
+ # None means "left at its default", so only an explicit
durable=True/False warns that it has no
+ # effect here. The operators only forward durable when it is not None.
+ if durable is not None:
warnings.warn(
"`durable` has no effect on Airflow versions below 3.3.",
UserWarning,
diff --git
a/providers/common/compat/tests/unit/common/compat/test__resumable_job_mixin.py
b/providers/common/compat/tests/unit/common/compat/test__resumable_job_mixin.py
index 31c0a861355..5dc9a967d4c 100644
---
a/providers/common/compat/tests/unit/common/compat/test__resumable_job_mixin.py
+++
b/providers/common/compat/tests/unit/common/compat/test__resumable_job_mixin.py
@@ -67,10 +67,11 @@ def test_stand_in_is_used_below_airflow_3_3():
class TestStandIn:
- def test_durable_left_at_default_does_not_warn(self):
+ @pytest.mark.parametrize("durable_kwargs", [{}, {"durable": None}],
ids=["omitted", "none"])
+ def test_durable_left_at_default_does_not_warn(self, durable_kwargs):
with warnings.catch_warnings():
warnings.simplefilter("error")
- operator = _JobOperator(task_id="t")
+ operator = _JobOperator(task_id="t", **durable_kwargs)
assert operator.durable is False
assert operator.base_kwargs == {"task_id": "t"}