This is an automated email from the ASF dual-hosted git repository.
ashb 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 f0cde671827 Use "Airflow versions" in user-facing docs, not "cores"
(#74045)
f0cde671827 is described below
commit f0cde671827a4b8f19aaf3d7db41503f05882351
Author: Ash Berlin-Taylor <[email protected]>
AuthorDate: Thu Oct 1 16:40:50 2026 +0100
Use "Airflow versions" in user-facing docs, not "cores" (#74045)
"cores", espeically when not capitalized imparts a lot of meaning to
that users won't be aware of. In user facing docs we should use terms
they are familiar with.
Before:
> its operators import-raise on older cores
After:
> its operators import-raise on older Airflow versions
Some places in task-sdk, it makes more sense to use the full package
name (`apache-airflow-core`) but that is rarer. In providers, even in
code comments, "Airflow versions" makes more sense.
---
airflow-core/newsfragments/68496.significant.rst | 4 ++--
.../airflow_e2e_tests/openlineage_tests/README.md | 2 +-
.../dags_extra/e2e_versioned_bundle.py | 4 ++--
.../airflow_breeze/commands/testing_commands.py | 2 +-
providers/common/ai/docs/approval_gates.rst | 2 +-
providers/common/ai/docs/installation.rst | 8 ++++----
providers/common/ai/docs/operators/agent.rst | 2 +-
providers/common/ai/docs/operators/llm_branch.rst | 2 +-
providers/common/ai/docs/troubleshooting.rst | 8 ++++----
.../airflow/providers/common/ai/mixins/approval.py | 6 +++---
.../airflow/providers/common/ai/operators/agent.py | 20 +++++++++---------
.../airflow/providers/common/ai/operators/llm.py | 17 ++++++++-------
.../providers/common/ai/utils/usage_budget.py | 6 +++---
.../tests/unit/common/ai/decorators/test_agent.py | 2 +-
.../ai/tests/unit/common/ai/durable/test_base.py | 2 +-
.../common/ai/durable/test_task_state_store.py | 2 +-
.../tests/unit/common/ai/mixins/test_approval.py | 4 ++--
.../tests/unit/common/ai/operators/test_agent.py | 10 ++++-----
.../ai/tests/unit/common/ai/operators/test_llm.py | 24 +++++++++++-----------
.../unit/common/ai/operators/test_llm_branch.py | 4 ++--
.../common/ai/operators/test_llm_file_analysis.py | 6 +++---
.../tests/unit/common/ai/operators/test_llm_sql.py | 4 ++--
.../common/compat/security/test_access_view.py | 8 ++++----
providers/fab/pyproject.toml | 2 +-
.../providers/fab/auth_manager/fab_auth_manager.py | 4 ++--
.../smtp/src/airflow/providers/smtp/hooks/smtp.py | 2 +-
.../airflow/providers/standard/operators/hitl.py | 6 +++---
.../tests/unit/standard/operators/test_hitl.py | 4 ++--
task-sdk/src/airflow/sdk/serde/__init__.py | 7 +++----
29 files changed, 86 insertions(+), 88 deletions(-)
diff --git a/airflow-core/newsfragments/68496.significant.rst
b/airflow-core/newsfragments/68496.significant.rst
index 5e0d3225764..ef0ee519977 100644
--- a/airflow-core/newsfragments/68496.significant.rst
+++ b/airflow-core/newsfragments/68496.significant.rst
@@ -1,12 +1,12 @@
Default async Postgres driver changed from asyncpg to psycopg3
-When ``[database] sql_alchemy_conn_async`` is not set, Airflow derives the
async metadata database URL from ``sql_alchemy_conn``. For PostgreSQL, the
derived URL now uses psycopg3 (``postgresql+psycopg_async://``) instead of
asyncpg (``postgresql+asyncpg://``) when psycopg3 is installed. If psycopg3 is
not installed — for example with an older ``apache-airflow-providers-postgres``
release that ships ``asyncpg`` but not ``psycopg`` — the derived URL keeps
using asyncpg, so upgrading core [...]
+When ``[database] sql_alchemy_conn_async`` is not set, Airflow derives the
async metadata database URL from ``sql_alchemy_conn``. For PostgreSQL, the
derived URL now uses psycopg3 (``postgresql+psycopg_async://``) instead of
asyncpg (``postgresql+asyncpg://``) when psycopg3 is installed. If psycopg3 is
not installed — for example with an older ``apache-airflow-providers-postgres``
release that ships ``asyncpg`` but not ``psycopg`` — the derived URL keeps
using asyncpg, so upgrading ``apa [...]
**Why:** Airflow recommends running PgBouncer in front of PostgreSQL in
production. asyncpg uses named server-side prepared statements, which break
under transaction-mode PgBouncer unless prepared-statement caching is
explicitly disabled. psycopg3 is safe behind transaction-mode PgBouncer with no
extra configuration, so the default async engine now works out of the box in
recommended production deployments.
The SQLite (``aiosqlite``) and MySQL (``aiomysql``) async URL derivations are
unchanged, and an explicitly configured ``sql_alchemy_conn_async`` is never
rewritten.
-**Packaging:** the ``apache-airflow-providers-postgres`` distribution now
installs ``psycopg`` (psycopg3) by default, and ``asyncpg`` is no longer
installed by default. Instead, it moved to the ``asyncpg`` optional extra. Note
that Airflow versions older than 3.4.0 always derive an asyncpg URL (they have
no psycopg3 fallback), so running the new provider release on an older core
requires either the ``asyncpg`` extra or an explicitly configured
``sql_alchemy_conn_async``.
+**Packaging:** the ``apache-airflow-providers-postgres`` distribution now
installs ``psycopg`` (psycopg3) by default, and ``asyncpg`` is no longer
installed by default. Instead, it moved to the ``asyncpg`` optional extra. Note
that Airflow versions older than 3.4.0 always derive an asyncpg URL (they have
no psycopg3 fallback), so running the new provider release on an older Airflow
version requires either the ``asyncpg`` extra or an explicitly configured
``sql_alchemy_conn_async``.
**To keep using asyncpg**, install the extra and configure the async URL
explicitly:
diff --git
a/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/README.md
b/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/README.md
index cadf25c399b..dce0ab17838 100644
--- a/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/README.md
+++ b/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/README.md
@@ -82,7 +82,7 @@ main) or when a maintainer sets the **`full tests needed`**
label on the PR (bot
Some DAGs require a newer Airflow than the compat targets and are dropped for
older versions in
`prepare_dags.py` (`MIN_AIRFLOW_VERSION_FOR_DAG`) — e.g.
`example_openlineage_hitl_dag` needs 3.1+
-(its operators import-raise on older cores). Add an entry there when a new DAG
is version-gated.
+(its operators import-raise on older Airflow versions). Add an entry there
when a new DAG is version-gated.
## Layout
diff --git
a/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/dags_extra/e2e_versioned_bundle.py
b/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/dags_extra/e2e_versioned_bundle.py
index 20d1c022e45..b11b213031f 100644
---
a/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/dags_extra/e2e_versioned_bundle.py
+++
b/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/dags_extra/e2e_versioned_bundle.py
@@ -53,10 +53,10 @@ class MockVersionedLocalDagBundle(LocalDagBundle):
digest.update(str(dag_file.stat().st_size).encode())
version = digest.hexdigest()[:12]
try:
- # Preferred on newer cores; bare str is deprecated for versioned
bundles.
+ # Preferred on newer Airflow versions; bare str is deprecated for
versioned bundles.
from airflow.dag_processing.bundles.base import BundleVersion
return BundleVersion(version=version)
except ImportError:
- # Older Airflow cores (compat runs) predate BundleVersion — a bare
string still works.
+ # Older Airflow versions (compat runs) predate BundleVersion — a
bare string still works.
return version
diff --git a/dev/breeze/src/airflow_breeze/commands/testing_commands.py
b/dev/breeze/src/airflow_breeze/commands/testing_commands.py
index 21d9a41b4ca..d9032c6422b 100644
--- a/dev/breeze/src/airflow_breeze/commands/testing_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/testing_commands.py
@@ -1455,7 +1455,7 @@ OPENLINEAGE_E2E_COMPAT_PROVIDERS = ["openlineage",
"standard", "common.compat",
def _build_openlineage_e2e_compat_image(airflow_version: str, python: str) ->
str:
"""Build a lightweight image: released ``apache/airflow:<version>`` +
current OL providers from main.
- Replicates the provider-compatibility approach (current provider code on
an older Airflow core)
+ Replicates the provider-compatibility approach (current provider code on
an older Airflow version)
without a full PROD image build — the released image is pulled and the
providers are reinstalled
from wheels built from main.
"""
diff --git a/providers/common/ai/docs/approval_gates.rst
b/providers/common/ai/docs/approval_gates.rst
index 386822f969a..39b16ea09b5 100644
--- a/providers/common/ai/docs/approval_gates.rst
+++ b/providers/common/ai/docs/approval_gates.rst
@@ -32,7 +32,7 @@ approving with ``allow_modifications=True``, and set a
deadline with
``approval_timeout``.
Human-in-the-loop review needs Airflow 3.1+, whether ``require_approval`` or a
-``decision_policy`` with ``on_uncertain="review"`` opens it. On an older core
the
+``decision_policy`` with ``on_uncertain="review"`` opens it. On an older
Airflow version the
operator raises ``AirflowOptionalProviderFeatureException`` when it is
constructed, so the Dag file
fails to import, and with it every Dag defined in that file. A dynamically
mapped
task (``.expand()``) is only constructed when it runs, so there the same error
diff --git a/providers/common/ai/docs/installation.rst
b/providers/common/ai/docs/installation.rst
index 483defafdf6..77e8b4e3e1f 100644
--- a/providers/common/ai/docs/installation.rst
+++ b/providers/common/ai/docs/installation.rst
@@ -62,7 +62,7 @@ package each extra installs.
Features gated on the Airflow version
-------------------------------------
-The provider runs on Airflow 2.11, but some features need a newer core:
+The provider runs on Airflow 2.11, but some features need a newer Airflow
version:
.. list-table::
:header-rows: 1
@@ -74,7 +74,7 @@ The provider runs on Airflow 2.11, but some features need a
newer core:
- Airflow 3.0
* - :doc:`Approval gates <approval_gates>` and :doc:`HITL review
<hitl_review>`
- Airflow 3.1
- * - The **Model** field in the connection form; on older cores put the
model in
+ * - The **Model** field in the connection form; on older Airflow versions
put the model in
**Extra**, for example ``{"model": "openai:gpt-5"}``
- Airflow 3.2
* - :doc:`Retry policies <retry_policies>`
@@ -82,11 +82,11 @@ The provider runs on Airflow 2.11, but some features need a
newer core:
* - :doc:`Durable execution <durable_execution>` without configuring
``[common.ai] durable_cache_path`` (the task state store)
- Airflow 3.3
- * - :doc:`Tool approval <tool_approval>` that pauses the task; on older
cores a tool
+ * - :doc:`Tool approval <tool_approval>` that pauses the task; on older
Airflow versions a tool
marked for approval fails the task
- Airflow 3.3
* - A :doc:`structured output <structured_output>` reaching downstream
tasks as the
- Pydantic model; on older cores it arrives as a ``dict``
+ Pydantic model; on older Airflow versions it arrives as a ``dict``
- Airflow 3.3
Airflow 2.11
diff --git a/providers/common/ai/docs/operators/agent.rst
b/providers/common/ai/docs/operators/agent.rst
index 3852d3de5f5..80c87facfe5 100644
--- a/providers/common/ai/docs/operators/agent.rst
+++ b/providers/common/ai/docs/operators/agent.rst
@@ -423,7 +423,7 @@ Parameters
- ``durable``: When ``True``, enables step-level caching of model responses and
tool results. On retry, cached steps are replayed instead of re-executing
expensive LLM calls. On Airflow >= 3.3 the cache uses the task state store
(no
- configuration needed); on older cores it requires the ``[common.ai]
+ configuration needed); on older Airflow versions it requires the
``[common.ai]
durable_cache_path`` config option to be set. Default ``False``. A replayed
step adds nothing to the usage counted against ``usage_limits`` or reported
in the ``usage`` XCom -- not its request, tokens, cost, or tool calls -- so
diff --git a/providers/common/ai/docs/operators/llm_branch.rst
b/providers/common/ai/docs/operators/llm_branch.rst
index 9e572d21e0e..6b07b1949a2 100644
--- a/providers/common/ai/docs/operators/llm_branch.rst
+++ b/providers/common/ai/docs/operators/llm_branch.rst
@@ -224,7 +224,7 @@ Four situations, each with a defined outcome:
Without a ``min_confidence`` on the policy nothing here applies and the
operator behaves as before. ``on_uncertain="review"`` needs Airflow 3.1+, like
-``require_approval``, and is rejected at construction on an older core. The
+``require_approval``, and is rejected at construction on an older Airflow
version. The
review it opens is the same one ``require_approval`` opens:
``approval_timeout``,
``on_approval_timeout``, ``allow_modifications``, ``approval_notifiers`` and
``approval_assigned_users`` all apply to it.
diff --git a/providers/common/ai/docs/troubleshooting.rst
b/providers/common/ai/docs/troubleshooting.rst
index 1d5001d3ce3..9a0694fbc6b 100644
--- a/providers/common/ai/docs/troubleshooting.rst
+++ b/providers/common/ai/docs/troubleshooting.rst
@@ -99,8 +99,8 @@ as a task failure.
``require_approval=True needs Airflow 3.1+`` /
``DecisionPolicy(on_uncertain='review') needs Airflow 3.1+`` /
``approval_assigned_users needs Airflow 3.1+`` / ``Human in the loop
functionality needs Airflow 3.1+``
Human-in-the-loop review, whether through ``require_approval``,
``DecisionPolicy(on_uncertain="review")`` or ``enable_hitl_review``, needs
Airflow 3.1
- or later. Upgrade the core, or use ``on_uncertain="fail"`` and drop the
review flags
- on an older core. See :doc:`approval_gates` and :doc:`hitl_review`.
+ or later. Upgrade Airflow, or use ``on_uncertain="fail"`` and drop the
review flags
+ on an older Airflow version. See :doc:`approval_gates` and
:doc:`hitl_review`.
``durable=True and enable_hitl_review=True cannot be used together`` /
``durable=True and code_mode=True cannot be used together``
Durable replay assumes a stable step order across attempts, which neither
a human
@@ -134,7 +134,7 @@ Run-time errors
above.
``durable=True`` on Airflow below 3.3 fails with a ``ValueError`` about
``durable_cache_path``
- On cores older than 3.3 the step cache lives in object storage and
+ On Airflow versions older than 3.3 the step cache lives in object storage
and
``[common.ai] durable_cache_path`` must be set. On 3.3 and later the task
state store
is used and the option is ignored. See :doc:`durable_execution`.
@@ -148,7 +148,7 @@ A structured ``output_type`` arrives downstream as a string
or fails to deserial
A review task waits for a long time
That is expected: the task is waiting for a reviewer. An approval gate on
an LLM operator
releases its worker slot while it waits (it pauses as awaiting input on
Airflow 3.3+, and
- defers to the triggerer on older cores); a HITL review on
``AgentOperator`` polls from the
+ defers to the triggerer on older Airflow versions); a HITL review on
``AgentOperator`` polls from the
worker and holds its slot. Set ``approval_timeout`` or ``hitl_timeout`` so
an unattended
review cannot wait forever. See :doc:`approval_gates` and
:doc:`hitl_review`.
diff --git
a/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py
b/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py
index 49e02d2f3b5..dc33aef7b73 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py
@@ -30,7 +30,7 @@ from airflow.providers.common.compat.version_compat import
AIRFLOW_V_3_3_PLUS
if AIRFLOW_V_3_3_PLUS:
# On Airflow 3.3+ the review parks the task in the first-class
AWAITING_INPUT state instead
- # of deferring to a trigger. On older cores this name is absent and
defer() is used.
+ # of deferring to a trigger. On older Airflow versions this name is absent
and defer() is used.
from airflow.sdk.exceptions import TaskAwaitingInput
log = logging.getLogger(__name__)
@@ -253,7 +253,7 @@ class LLMApprovalMixin:
continuation["decision"] = decision
if AIRFLOW_V_3_3_PLUS:
- # New core (3.3+): park the task in AWAITING_INPUT -- no trigger,
no triggerer. The
+ # Airflow 3.3+: park the task in AWAITING_INPUT -- no trigger, no
triggerer. The
# task is resumed by the Core API response handler or the
scheduler timeout sweep.
raise TaskAwaitingInput(
method_name="execute_complete",
@@ -261,7 +261,7 @@ class LLMApprovalMixin:
timeout=self.approval_timeout,
)
- # Fallback for cores < 3.3: defer the response check to HITLTrigger on
the triggerer.
+ # Fallback for Airflow versions < 3.3: defer the response check to
HITLTrigger on the triggerer.
self.defer(
trigger=HITLTrigger(
ti_id=ti_id,
diff --git
a/providers/common/ai/src/airflow/providers/common/ai/operators/agent.py
b/providers/common/ai/src/airflow/providers/common/ai/operators/agent.py
index 4f13ad4bf0d..11470872e0d 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/operators/agent.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/operators/agent.py
@@ -78,17 +78,17 @@ from airflow.providers.common.compat.version_compat import
AIRFLOW_V_3_1_PLUS, A
from airflow.providers.standard.exceptions import HITLTimeoutError,
HITLTriggerEventError
if AIRFLOW_V_3_3_PLUS:
- # Per-tool approval parks the task in AWAITING_INPUT, which older cores do
not have.
+ # Per-tool approval parks the task in AWAITING_INPUT, which older Airflow
versions do not have.
from airflow.sdk.exceptions import TaskAwaitingInput
from airflow.sdk.execution_time.context import NEVER_EXPIRE
from airflow.sdk.execution_time.hitl import upsert_hitl_detail
try:
- # See LLMOperator: new enough cores register declared ``output_type``
classes
+ # See LLMOperator: Newer ``apache-airflow-task-sdk`` versions register
declared ``output_type`` classes
# from a worker-side DAG walk, so the model instance flows through XCom;
older
- # cores dump to a dict instead.
+ # ``apache-airflow-task-sdk`` versions without the walk dump to a dict
instead.
from airflow.sdk.serde import SUPPORTS_OPERATOR_DESERIALIZATION_WALKER as
_CORE_WALKER
-except ImportError: # pragma: no cover - cores before the worker-side
registration walk
+except ImportError: # pragma: no cover - missing ``apache-airflow-task-sdk``
walker
_CORE_WALKER = False
if TYPE_CHECKING:
@@ -341,7 +341,7 @@ class AgentOperator(CancellableAgentRunMixin, BaseOperator,
HITLReviewMixin):
attempts left behind, and whatever the rerun replays from that cache
is free.
On Airflow >= 3.3 the cache is kept in the AIP-103 task state store, so
- no extra configuration is needed. On older cores it is persisted to
+ no extra configuration is needed. On older Airflow versions it is
persisted to
ObjectStorage and requires ``[common.ai] durable_cache_path`` to be
set.
Tools are durably cached when provided via ``toolsets=`` or via a
concrete pydantic-ai ``Toolset`` capability. Tools reaching the agent
@@ -515,7 +515,7 @@ class AgentOperator(CancellableAgentRunMixin, BaseOperator,
HITLReviewMixin):
self.system_prompt = system_prompt
self.output_type = output_type
self.serialize_output = serialize_output
- # See LLMOperator: instance flows when the core registers
``output_type``
+ # See LLMOperator: instance flows when Airflow registers
``output_type``
# via its worker-side DAG walk; otherwise (or on opt-in) dump to a
dict.
self._serialize_model_output = serialize_output or not _CORE_WALKER
self.toolsets = toolsets
@@ -544,8 +544,8 @@ class AgentOperator(CancellableAgentRunMixin, BaseOperator,
HITLReviewMixin):
self._run_usage: RunUsage | None = None
self._run_usage_base: RunUsage = RunUsage()
- # Checked ahead of the combination rules below. On a core older than
3.1 the core
- # version is the real blocker, and reporting a combination error first
would send the
+ # Checked ahead of the combination rules below. When Airflow is older
than 3.1, its version
+ # is the real blocker, and reporting a combination error first would
send the
# user to drop an argument that was never the problem -- they would
hit this anyway.
if enable_hitl_review and not AIRFLOW_V_3_1_PLUS:
raise AirflowOptionalProviderFeatureException(
@@ -931,12 +931,12 @@ class AgentOperator(CancellableAgentRunMixin,
BaseOperator, HITLReviewMixin):
On Airflow >= 3.3 durable steps are cached in the AIP-103 task state
store, which handles persistence and large-value offload natively, so
no
- ``[common.ai] durable_cache_path`` is required. On older cores, fall
back
+ ``[common.ai] durable_cache_path`` is required. On older Airflow
versions, fall back
to the ObjectStorage backend configured via ``durable_cache_path``.
"""
if AIRFLOW_V_3_3_PLUS:
# Imported lazily: NEVER_EXPIRE and the task state store accessor
do
- # not exist on cores before 3.3.
+ # not exist on Airflow versions before 3.3.
from airflow.providers.common.ai.durable.task_state_store import
TaskStateStoreDurableStorage
return TaskStateStoreDurableStorage(context["task_state_store"])
diff --git
a/providers/common/ai/src/airflow/providers/common/ai/operators/llm.py
b/providers/common/ai/src/airflow/providers/common/ai/operators/llm.py
index d54a089acc7..f2ce27a315a 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/operators/llm.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/operators/llm.py
@@ -52,12 +52,11 @@ from airflow.providers.common.compat.version_compat import
AIRFLOW_V_3_1_PLUS
from airflow.providers.standard.exceptions import HITLRejectException,
HITLTimeoutError
try:
- # New enough cores register an operator's declared ``output_type`` classes
for
- # XCom deserialization from a worker-side walk over the loaded DAG. On
those
- # cores the model instance flows through XCom unchanged. Older cores lack
that
- # walk, so the operator dumps to a dict instead (still deserializable
anywhere).
+ # The worker-side DAG walk registers operator-declared ``output_type``
classes
+ # for XCom deserialization. ``apache-airflow-task-sdk`` versions with this
walk
+ # send model instances unchanged; older versions dump them to a dict
instead.
from airflow.sdk.serde import SUPPORTS_OPERATOR_DESERIALIZATION_WALKER as
_CORE_WALKER
-except ImportError: # pragma: no cover - cores before the worker-side
registration walk
+except ImportError: # pragma: no cover - missing ``apache-airflow-task-sdk``
walker
_CORE_WALKER = False
if TYPE_CHECKING:
@@ -226,7 +225,7 @@ class LLMOperator(CancellableAgentRunMixin, BaseOperator,
LLMApprovalMixin):
self.system_prompt = system_prompt
self.output_type = output_type
self.serialize_output = serialize_output
- # Return the Pydantic instance when the core can register
``output_type``
+ # Return the Pydantic instance when ``apache-airflow-task-sdk`` can
register ``output_type``
# for deserialization (its worker-side DAG walk); otherwise, or when
the
# user opts in, dump to a dict so the value is deserializable anywhere.
self._serialize_model_output = serialize_output or not _CORE_WALKER
@@ -237,13 +236,13 @@ class LLMOperator(CancellableAgentRunMixin, BaseOperator,
LLMApprovalMixin):
raise ValueError(
f"on_approval_timeout must be 'fail', 'approve', or 'reject',
got {on_approval_timeout!r}."
)
- # Checked before the combination rule so an old core reports the core
version
+ # Checked before the combination rule so an older Airflow version
reports the Airflow version
# rather than sending the user to drop an argument that was never the
problem.
if require_approval and not AIRFLOW_V_3_1_PLUS:
raise
AirflowOptionalProviderFeatureException("require_approval=True needs Airflow
3.1+.")
if self.decision_policy.reviews and not AIRFLOW_V_3_1_PLUS:
raise AirflowOptionalProviderFeatureException(
- "DecisionPolicy(on_uncertain='review') needs Airflow 3.1+; use
on_uncertain='fail' on this core."
+ "DecisionPolicy(on_uncertain='review') needs Airflow 3.1+; use
on_uncertain='fail' on Airflow versions older than 3.1."
)
# A review can open either way; both settings make the approval flow
reachable.
@@ -346,7 +345,7 @@ class LLMOperator(CancellableAgentRunMixin, BaseOperator,
LLMApprovalMixin):
self.defer_for_approval(context, output, body=body,
decision=record) # type: ignore[misc]
if self._serialize_model_output and isinstance(output, BaseModel):
- # ``serialize_output=True``, or a core without the worker-side
+ # ``serialize_output=True``, or an ``apache-airflow-task-sdk``
version without the worker-side
# deserialization-class walk: dump to a dict so XCom carries a
plain
# JSON payload that deserializes without an allow-list entry.
output = output.model_dump()
diff --git
a/providers/common/ai/src/airflow/providers/common/ai/utils/usage_budget.py
b/providers/common/ai/src/airflow/providers/common/ai/utils/usage_budget.py
index f67c686fa99..cb8c43e412e 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/utils/usage_budget.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/utils/usage_budget.py
@@ -22,7 +22,7 @@ Cross-attempt ``pydantic_ai.usage.RunUsage`` accounting,
backed by the task stat
``dataclasses.fields`` rather than hard-coding the field list so a future
pydantic-ai field is carried through automatically. This module has no
top-level import of any Airflow >= 3.3-only symbol: it must stay importable on
-older cores, even though :class:`TaskStateStoreUsageBudget` is only
+older Airflow versions, even though :class:`TaskStateStoreUsageBudget` is only
constructed on 3.3+ (see ``AgentOperator._build_usage_budget``).
"""
@@ -194,8 +194,8 @@ class TaskStateStoreUsageBudget:
def save(self, usage: RunUsage) -> None:
"""Best-effort write; a failure here must never fail the task, only
the caller's raise matters."""
try:
- # NEVER_EXPIRE does not exist on cores before 3.3; imported lazily
here so this
- # module keeps importing cleanly on older cores (this module's
docstring).
+ # NEVER_EXPIRE does not exist on Airflow versions before 3.3;
imported lazily here so this
+ # module keeps importing cleanly on older Airflow versions (this
module's docstring).
from airflow.sdk.execution_time.context import NEVER_EXPIRE
record: dict[str, Any] = {
diff --git a/providers/common/ai/tests/unit/common/ai/decorators/test_agent.py
b/providers/common/ai/tests/unit/common/ai/decorators/test_agent.py
index a04ec481c4b..fffdd51a15f 100644
--- a/providers/common/ai/tests/unit/common/ai/decorators/test_agent.py
+++ b/providers/common/ai/tests/unit/common/ai/decorators/test_agent.py
@@ -36,7 +36,7 @@ except ImportError:
requires_typed_xcom = pytest.mark.skipif(
not _CORE_WALKER,
- reason="Requires a core with the worker-side deserialization-class walk.",
+ reason="Requires an ``apache-airflow-task-sdk`` version with the
worker-side deserialization-class walk.",
)
diff --git a/providers/common/ai/tests/unit/common/ai/durable/test_base.py
b/providers/common/ai/tests/unit/common/ai/durable/test_base.py
index 928e856dc91..20826fd277c 100644
--- a/providers/common/ai/tests/unit/common/ai/durable/test_base.py
+++ b/providers/common/ai/tests/unit/common/ai/durable/test_base.py
@@ -39,7 +39,7 @@ class TestRealBackendsSatisfyProtocol:
@pytest.mark.skipif(not AIRFLOW_V_3_3_PLUS, reason="task state store
backend requires Airflow >= 3.3")
def test_task_state_store_backend_satisfies_protocol(self):
- # Imported inside the test: this module runs on all cores, but
+ # Imported inside the test: this module runs on all supported Airflow
versions, but
# ``task_state_store`` pulls in ``NEVER_EXPIRE``, which only exists on
3.3+.
from airflow.providers.common.ai.durable.task_state_store import
TaskStateStoreDurableStorage
diff --git
a/providers/common/ai/tests/unit/common/ai/durable/test_task_state_store.py
b/providers/common/ai/tests/unit/common/ai/durable/test_task_state_store.py
index 9e56354fc59..e6990be2ffd 100644
--- a/providers/common/ai/tests/unit/common/ai/durable/test_task_state_store.py
+++ b/providers/common/ai/tests/unit/common/ai/durable/test_task_state_store.py
@@ -23,7 +23,7 @@ import pytest
from tests_common.test_utils.version_compat import AIRFLOW_V_3_3_PLUS
if not AIRFLOW_V_3_3_PLUS:
- # ``airflow.sdk.execution_time.context`` exists on older cores, but
``NEVER_EXPIRE``
+ # ``airflow.sdk.execution_time.context`` exists on older Airflow versions,
but ``NEVER_EXPIRE``
# (imported transitively via ``task_state_store``) only lands in 3.3, so an
# ``importorskip`` on the module is not enough -- gate on the version
instead.
pytest.skip("task state store needs Airflow >= 3.3",
allow_module_level=True)
diff --git a/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py
b/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py
index 85123748ff6..834c00d2610 100644
--- a/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py
+++ b/providers/common/ai/tests/unit/common/ai/mixins/test_approval.py
@@ -103,8 +103,8 @@ def context():
return {"task_instance": ti, "dag": DAG("test_dag")}
-# The legacy trigger path is taken on cores < 3.3; pin the flag so these tests
keep
-# exercising the defer() fallback when run against newer cores.
+# The legacy trigger path is taken on Airflow versions < 3.3; pin the flag so
these tests keep
+# exercising the defer() fallback when run against newer Airflow versions.
@patch(AWAIT_INPUT_FLAG_PATH, False)
class TestDeferForApproval:
@patch(HITL_TRIGGER_PATH, autospec=True)
diff --git a/providers/common/ai/tests/unit/common/ai/operators/test_agent.py
b/providers/common/ai/tests/unit/common/ai/operators/test_agent.py
index e344947308e..2d3422f2479 100644
--- a/providers/common/ai/tests/unit/common/ai/operators/test_agent.py
+++ b/providers/common/ai/tests/unit/common/ai/operators/test_agent.py
@@ -105,7 +105,7 @@ except ImportError:
requires_typed_xcom = pytest.mark.skipif(
not _CORE_WALKER,
- reason="Requires a core with the worker-side deserialization-class walk.",
+ reason="Requires an ``apache-airflow-task-sdk`` version with the
worker-side deserialization-class walk.",
)
@@ -164,7 +164,7 @@ def _make_task_state_store_accessor():
``TaskStateStoreAccessor`` doesn't exist below Airflow 3.3; several
callers of this
helper exercise ``execute()`` paths (e.g. ``usage_limits`` forwarding)
that don't
- depend on the task state store at all on those cores --
``_build_usage_budget``
+ depend on the task state store at all on those Airflow versions --
``_build_usage_budget``
returns ``None`` before ever touching ``context["task_state_store"]``.
Falling back
to a plain method-name spec keeps this helper importable there too,
instead of
forcing every caller to skip on Airflow version for a dependency they
don't have.
@@ -1495,7 +1495,7 @@ class TestAgentOperatorDurable:
@pytest.mark.skipif(not AIRFLOW_V_3_3_PLUS, reason="task state store
backend requires Airflow >= 3.3")
def test_build_durable_storage_uses_task_state_store_on_3_3(self):
"""On Airflow >= 3.3 the cache lives in the task state store -- no
durable_cache_path needed."""
- # Imported inside the test: this module runs on all cores, but both
symbols
+ # Imported inside the test: this module runs on all supported Airflow
versions, but both symbols
# (and ``NEVER_EXPIRE``, pulled in by ``task_state_store``) only exist
on 3.3+.
from airflow.providers.common.ai.durable.task_state_store import
TaskStateStoreDurableStorage
from airflow.sdk.execution_time.context import TaskStateStoreAccessor
@@ -1979,11 +1979,11 @@ class TestAgentOperatorHITLArgumentChecks:
)
@patch("airflow.providers.common.ai.operators.agent.AIRFLOW_V_3_1_PLUS",
False)
def test_version_gate_reported_before_combination_errors(self,
conflicting_kwargs):
- """On a core older than 3.1 the core version is the blocker, so it is
what is reported.
+ """When Airflow is older than 3.1, its version is the blocker, so it
is what is reported.
Dropping the conflicting argument would not make the operator work
there, so reporting
the combination error first sends the user to the wrong knob. This
ordering is also why
- the combination tests above carry a 3.1 skipif: on an older core they
raise this instead.
+ the combination tests above carry a 3.1 skipif: on an older Airflow
version they raise this instead.
"""
with pytest.raises(AirflowOptionalProviderFeatureException,
match="Airflow 3.1"):
AgentOperator(
diff --git a/providers/common/ai/tests/unit/common/ai/operators/test_llm.py
b/providers/common/ai/tests/unit/common/ai/operators/test_llm.py
index bf87665a0a6..b1cee57b5dd 100644
--- a/providers/common/ai/tests/unit/common/ai/operators/test_llm.py
+++ b/providers/common/ai/tests/unit/common/ai/operators/test_llm.py
@@ -48,9 +48,9 @@ from airflow.providers.common.compat.sdk import
AirflowOptionalProviderFeatureEx
from airflow.providers.standard.exceptions import HITLRejectException,
HITLTimeoutError
if AIRFLOW_V_3_3_PLUS:
- # On 3.3+ cores require_approval pauses the task in AWAITING_INPUT; older
cores defer
+ # On Airflow 3.3+ require_approval pauses the task in AWAITING_INPUT;
older Airflow versions defer
# to HITLTrigger. Both exceptions carry method_name/kwargs/timeout, so the
approval
- # tests assert against whichever pause signal the running core uses.
+ # tests assert against whichever pause signal the running Airflow version
uses.
from airflow.sdk.exceptions import TaskAwaitingInput as ApprovalPauseSignal
else:
ApprovalPauseSignal = TaskDeferred # type: ignore[assignment, misc]
@@ -58,11 +58,11 @@ else:
AWAIT_INPUT_FLAG_PATH =
"airflow.providers.common.ai.mixins.approval.AIRFLOW_V_3_3_PLUS"
# Returning the Pydantic instance through XCom (rather than a dict) only
happens
-# on cores that register declared ``output_type`` classes from the worker-side
-# DAG walk. On older cores the operator dumps to a dict, so these tests skip.
+# on ``apache-airflow-task-sdk`` versions that register declared
``output_type`` classes from the worker-side
+# DAG walk. On older ``apache-airflow-task-sdk`` versions the operator dumps
to a dict, so these tests skip.
requires_typed_xcom = pytest.mark.skipif(
not _CORE_WALKER,
- reason="Requires a core with the worker-side deserialization-class walk.",
+ reason="Requires an ``apache-airflow-task-sdk`` version with the
worker-side deserialization-class walk.",
)
@@ -341,7 +341,7 @@ class TestLLMOperator:
def test_declares_output_type_for_deserialization(self):
"""Declares ``output_type`` so the worker-side DAG walk registers it
for deserialization.
- Registration happens in the core walk over the loaded DAG (covered by
the
+ Registration happens in the worker-side walk over the loaded DAG
(covered by the
task-runner tests), not as an ``__init__`` side effect.
"""
assert "output_type" in
LLMOperator.deserialization_allowed_class_fields
@@ -607,7 +607,7 @@ class TestLLMOperatorConfidenceGate:
LLMOperator(
task_id="t", prompt="p", llm_conn_id="c",
decision_policy=DecisionPolicy(min_confidence=0.7)
)
- # "fail" never opens a review, so it builds on any core.
+ # "fail" never opens a review, so it builds on any Airflow version.
LLMOperator(
task_id="t",
prompt="p",
@@ -706,11 +706,11 @@ class TestLLMOperatorConfidenceGate:
class TestLLMOperatorApprovalVersionGate:
- """__init__ rejects require_approval on cores without human-in-the-loop
support.
+ """__init__ rejects require_approval on Airflow versions without
human-in-the-loop support.
- Deliberately carries no class-level 3.1 skipif. These tests simulate an
old core by
+ Deliberately carries no class-level 3.1 skipif. These tests simulate an
older Airflow version by
patching the flag, so they must not inherit the sibling class's skip --
and on a
- genuine pre-3.1 core, such as the 3.0.6 providers-compatibility job, they
are the
+ genuine pre-3.1 Airflow version, such as the 3.0.6 providers-compatibility
job, they are the
only tests that exercise the gate natively.
"""
@@ -741,7 +741,7 @@ class TestLLMOperatorApprovalVersionGate:
def test_old_core_reports_the_blocking_argument(self, kwargs,
expected_exception, match):
"""Which of two applicable errors __init__ reports, and in which order.
- Dropping on_approval_timeout would not make the operator work on an
older core,
+ Dropping on_approval_timeout would not make the operator work on an
older Airflow version,
so the version has to beat the combination rule. A bad literal is
wrong on every
core, so it keeps its own precise message -- which also pins the guard
below the
literal check, since hoisting it would swap that message for the
version one.
@@ -901,7 +901,7 @@ class TestLLMOperatorApproval:
def test_execute_with_approval_defers_on_legacy_core(
self, mock_hook_cls, mock_upsert, mock_trigger_cls,
make_mock_run_result
):
- """On cores < 3.3 (flag pinned), execute() falls back to deferring to
HITLTrigger."""
+ """On Airflow versions < 3.3 (flag pinned), execute() falls back to
deferring to HITLTrigger."""
mock_agent = MagicMock(spec=["run_sync"])
mock_agent.run_sync.return_value = make_mock_run_result("LLM response")
mock_hook_cls.get_hook.return_value.create_agent.return_value =
mock_agent
diff --git
a/providers/common/ai/tests/unit/common/ai/operators/test_llm_branch.py
b/providers/common/ai/tests/unit/common/ai/operators/test_llm_branch.py
index 2f75362aaec..0ea1dd6cb30 100644
--- a/providers/common/ai/tests/unit/common/ai/operators/test_llm_branch.py
+++ b/providers/common/ai/tests/unit/common/ai/operators/test_llm_branch.py
@@ -36,9 +36,9 @@ from airflow.providers.standard.operators.empty import
EmptyOperator
from tests_common.test_utils.version_compat import AIRFLOW_V_3_1_PLUS,
AIRFLOW_V_3_3_PLUS
if AIRFLOW_V_3_3_PLUS:
- # On 3.3+ cores require_approval pauses the task in AWAITING_INPUT; older
cores defer to
+ # On Airflow 3.3+ require_approval pauses the task in AWAITING_INPUT;
older Airflow versions defer to
# HITLTrigger. Both signals carry method_name/kwargs/timeout, so the
approval tests assert
- # against whichever pause signal the running core uses.
+ # against whichever pause signal the running Airflow version uses.
from airflow.sdk.exceptions import TaskAwaitingInput as ApprovalPauseSignal
else:
ApprovalPauseSignal = TaskDeferred # type: ignore[assignment, misc]
diff --git
a/providers/common/ai/tests/unit/common/ai/operators/test_llm_file_analysis.py
b/providers/common/ai/tests/unit/common/ai/operators/test_llm_file_analysis.py
index ccd29d0de53..e26b07358b8 100644
---
a/providers/common/ai/tests/unit/common/ai/operators/test_llm_file_analysis.py
+++
b/providers/common/ai/tests/unit/common/ai/operators/test_llm_file_analysis.py
@@ -32,9 +32,9 @@ from airflow.providers.common.compat.sdk import TaskDeferred
from tests_common.test_utils.version_compat import AIRFLOW_V_3_1_PLUS,
AIRFLOW_V_3_3_PLUS
if AIRFLOW_V_3_3_PLUS:
- # On 3.3+ cores require_approval pauses the task in AWAITING_INPUT; older
cores defer to
+ # On Airflow 3.3+ require_approval pauses the task in AWAITING_INPUT;
older Airflow versions defer to
# HITLTrigger. Both signals carry method_name/kwargs/timeout, so the
approval tests assert
- # against whichever pause signal the running core uses.
+ # against whichever pause signal the running Airflow version uses.
from airflow.sdk.exceptions import TaskAwaitingInput as ApprovalPauseSignal
else:
ApprovalPauseSignal = TaskDeferred # type: ignore[assignment, misc]
@@ -46,7 +46,7 @@ except ImportError:
requires_typed_xcom = pytest.mark.skipif(
not _CORE_WALKER,
- reason="Requires a core with the worker-side deserialization-class walk.",
+ reason="Requires an ``apache-airflow-task-sdk`` version with the
worker-side deserialization-class walk.",
)
diff --git a/providers/common/ai/tests/unit/common/ai/operators/test_llm_sql.py
b/providers/common/ai/tests/unit/common/ai/operators/test_llm_sql.py
index 1676cc114ae..208f439319c 100644
--- a/providers/common/ai/tests/unit/common/ai/operators/test_llm_sql.py
+++ b/providers/common/ai/tests/unit/common/ai/operators/test_llm_sql.py
@@ -37,9 +37,9 @@ from airflow.providers.common.sql.config import
DataSourceConfig
from tests_common.test_utils.version_compat import AIRFLOW_V_3_1_PLUS,
AIRFLOW_V_3_3_PLUS
if AIRFLOW_V_3_3_PLUS:
- # On 3.3+ cores require_approval pauses the task in AWAITING_INPUT; older
cores defer to
+ # On Airflow 3.3+ require_approval pauses the task in AWAITING_INPUT;
older Airflow versions defer to
# HITLTrigger. Both signals carry method_name/kwargs/timeout, so the
approval tests assert
- # against whichever pause signal the running core uses.
+ # against whichever pause signal the running Airflow version uses.
from airflow.sdk.exceptions import TaskAwaitingInput as ApprovalPauseSignal
else:
ApprovalPauseSignal = TaskDeferred # type: ignore[assignment, misc]
diff --git
a/providers/common/compat/tests/unit/common/compat/security/test_access_view.py
b/providers/common/compat/tests/unit/common/compat/security/test_access_view.py
index 2350b151397..88753d34f4c 100644
---
a/providers/common/compat/tests/unit/common/compat/security/test_access_view.py
+++
b/providers/common/compat/tests/unit/common/compat/security/test_access_view.py
@@ -29,9 +29,9 @@ ACCESS_VIEW_SHIM_MODULE =
"airflow.providers.common.compat.security.access_view"
@pytest.mark.parametrize("member_name", ["IMPORT_ERRORS_ALL",
"AUDIT_LOGS_ALL", "REPARSE_ALL"])
def test_resolves_to_the_core_access_view_member_or_none(member_name):
- """The shim mirrors the running core: the ``AccessView`` member on a core
that
+ """The shim mirrors the running Airflow version: the ``AccessView`` member
on an Airflow version that
defines it (>= 3.4.0), otherwise ``None``. Kept version-agnostic so it
holds
- across the whole provider compatibility matrix, including cores that
predate the
+ across the whole provider compatibility matrix, including Airflow versions
that predate the
member or lack ``api_fastapi`` entirely.
"""
shim = importlib.import_module(ACCESS_VIEW_SHIM_MODULE)
@@ -47,10 +47,10 @@ def
test_resolves_to_the_core_access_view_member_or_none(member_name):
def test_is_none_on_older_core_without_the_member():
- """On a core that predates the new ``AccessView`` members the shim
resolves to ``None``."""
+ """On an Airflow version that predates the new ``AccessView`` members the
shim resolves to ``None``."""
class _AccessViewWithoutNewMembers:
- """Stand-in for an older core AccessView that lacks the new members."""
+ """Stand-in for an AccessView in older Airflow versions that lacks the
new members."""
fake_resource_details = types.ModuleType(RESOURCE_DETAILS_MODULE)
fake_resource_details.AccessView = _AccessViewWithoutNewMembers
diff --git a/providers/fab/pyproject.toml b/providers/fab/pyproject.toml
index e75c766ca80..e42ba907381 100644
--- a/providers/fab/pyproject.toml
+++ b/providers/fab/pyproject.toml
@@ -80,7 +80,7 @@ dependencies = [
# In particular, make sure any breaking changes, for example any new
methods, are accounted for.
"flask-appbuilder==5.2.2", # Whenever updating the version, run
test_fab_alignment.py to verify.
# Transitive via flask-appbuilder -> flask-jwt-extended; pinned here so
the FAB
- # provider keeps installing cleanly when paired with older airflow-core
releases
+ # provider keeps installing cleanly when paired with older
``apache-airflow-core`` releases
# (the compat-3.0.6 matrix job) whose own pyjwt floor predates
`jwt.types.Options`
# (added in PyJWT 2.11.0). Without this, `from jwt.types import Options` in
# `flask_jwt_extended.tokens` raises ImportError at module import time.
diff --git
a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
index 02819c5b110..01cc28d5670 100644
--- a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
+++ b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
@@ -156,8 +156,8 @@ _MAP_ACCESS_VIEW_TO_FAB_RESOURCE_TYPE = {
}
# ``AccessView.IMPORT_ERRORS_ALL`` and ``AccessView.AUDIT_LOGS_ALL`` only
exist on
-# core >= 3.4.0, and ``AccessView.REPARSE_ALL`` after it; the compat shim
yields ``None``
-# on older core so this provider still imports there.
+# Airflow >= 3.4.0, and ``AccessView.REPARSE_ALL`` in a later version; the
compat shim yields ``None``
+# on older Airflow versions so this provider still imports there.
if IMPORT_ERRORS_ALL_ACCESS_VIEW is not None:
_MAP_ACCESS_VIEW_TO_FAB_RESOURCE_TYPE[IMPORT_ERRORS_ALL_ACCESS_VIEW] =
RESOURCE_IMPORT_ERROR_ALL
if AUDIT_LOGS_ALL_ACCESS_VIEW is not None:
diff --git a/providers/smtp/src/airflow/providers/smtp/hooks/smtp.py
b/providers/smtp/src/airflow/providers/smtp/hooks/smtp.py
index 268b5e71f97..744fe705cb7 100644
--- a/providers/smtp/src/airflow/providers/smtp/hooks/smtp.py
+++ b/providers/smtp/src/airflow/providers/smtp/hooks/smtp.py
@@ -47,7 +47,7 @@ if TYPE_CHECKING:
def build_xoauth2_string(username: str, token: str) -> str:
- """Local fallback for older Airflow cores (≤2.11)."""
+ """Local fallback for older Airflow versions (≤2.11)."""
return f"user={username}\x01auth=Bearer {token}\x01\x01"
diff --git
a/providers/standard/src/airflow/providers/standard/operators/hitl.py
b/providers/standard/src/airflow/providers/standard/operators/hitl.py
index 62628b261fa..3ad7639ad98 100644
--- a/providers/standard/src/airflow/providers/standard/operators/hitl.py
+++ b/providers/standard/src/airflow/providers/standard/operators/hitl.py
@@ -46,7 +46,7 @@ from airflow.sdk.timezone import utcnow
if AIRFLOW_V_3_3_PLUS:
# On Airflow 3.3+ the operator parks the task in the first-class
AWAITING_INPUT state instead of
- # deferring to a trigger. On older cores this name is absent and the
defer() fallback is used.
+ # deferring to a trigger. On older Airflow versions this name is absent
and the defer() fallback is used.
from airflow.sdk.exceptions import TaskAwaitingInput
if TYPE_CHECKING:
@@ -232,7 +232,7 @@ class HITLOperator(BaseOperator):
notifier(context)
if AIRFLOW_V_3_3_PLUS:
- # New core (3.3+): park the task in AWAITING_INPUT -- no trigger,
no triggerer. The task
+ # Airflow 3.3+: park the task in AWAITING_INPUT -- no trigger, no
triggerer. The task
# is resumed by the Core API response handler or the scheduler
timeout sweep, so the
# triggerer no longer needs to run for Human-in-the-loop tasks to
make progress.
raise TaskAwaitingInput(
@@ -240,7 +240,7 @@ class HITLOperator(BaseOperator):
timeout=self.response_timeout,
)
- # Fallback for cores < 3.3: defer the response check to HITLTrigger on
the triggerer.
+ # Fallback for Airflow versions < 3.3: defer the response check to
HITLTrigger on the triggerer.
self.defer(
trigger=HITLTrigger(
ti_id=ti_id,
diff --git a/providers/standard/tests/unit/standard/operators/test_hitl.py
b/providers/standard/tests/unit/standard/operators/test_hitl.py
index 16220ccc203..b19b360568f 100644
--- a/providers/standard/tests/unit/standard/operators/test_hitl.py
+++ b/providers/standard/tests/unit/standard/operators/test_hitl.py
@@ -335,7 +335,7 @@ class TestHITLOperator:
"poke_interval": 5.0,
}
- @pytest.mark.skipif(not AIRFLOW_V_3_1_3_PLUS, reason="This only works in
airflow-core >= 3.1.3")
+ @pytest.mark.skipif(not AIRFLOW_V_3_1_3_PLUS, reason="This only works on
Airflow >= 3.1.3")
@pytest.mark.parametrize(
("input_params", "expected_params"),
[
@@ -393,7 +393,7 @@ class TestHITLOperator:
@pytest.mark.skipif(
AIRFLOW_V_3_1_3_PLUS,
- reason="Preserve the old behavior if airflow-core < 3.1.3. Otherwise
the UI will break.",
+ reason="Preserve the old behavior on Airflow versions < 3.1.3.
Otherwise the UI will break.",
)
def test_serialzed_params_legacy(self) -> None:
hitl_op = HITLOperator(
diff --git a/task-sdk/src/airflow/sdk/serde/__init__.py
b/task-sdk/src/airflow/sdk/serde/__init__.py
index f671545d3aa..1b0e06853a1 100644
--- a/task-sdk/src/airflow/sdk/serde/__init__.py
+++ b/task-sdk/src/airflow/sdk/serde/__init__.py
@@ -57,10 +57,9 @@ PYDANTIC_MODEL_QUALNAME = "pydantic.main.BaseModel"
DEFAULT_VERSION = 0
-# Signals that this Airflow registers operator-declared deserialization classes
-# from a worker-side walk over the loaded DAG (see the task runner), so
operators
-# do not need to register them as an ``__init__`` side effect. Providers probe
-# this to drop their back-compat ``__init__`` registration on new enough cores.
+# Signals that ``apache-airflow-task-sdk`` registers operator-declared
deserialization
+# classes during a worker-side walk over the loaded DAG (see the task runner).
Providers
+# probe this to drop their back-compat ``__init__`` registration when the SDK
supports the walk.
SUPPORTS_OPERATOR_DESERIALIZATION_WALKER = True
T = TypeVar("T", bool, float, int, dict, list, str, tuple, set)