This is an automated email from the ASF dual-hosted git repository.
gopidesu 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 a480f77e747 Make task-sdk compatible with mypy 1.16.1 (#53047)
a480f77e747 is described below
commit a480f77e747a02a99e2afa50519e2ffe08952f1a
Author: GPK <[email protected]>
AuthorDate: Fri Jul 11 14:06:59 2025 +0100
Make task-sdk compatible with mypy 1.16.1 (#53047)
* Make task-sdk compatible with mypy 1.16.1
* Fixup mypy
* Fixup mypy
* Update comment for typeguard usage in secrets_masker
* Resolve comments
* Resolve pre-commit
---
task-sdk/src/airflow/sdk/definitions/_internal/expandinput.py | 5 ++++-
task-sdk/src/airflow/sdk/definitions/asset/__init__.py | 4 ++--
.../src/airflow/sdk/definitions/decorators/setup_teardown.py | 9 +++++++--
task-sdk/src/airflow/sdk/definitions/taskgroup.py | 8 +++++++-
task-sdk/src/airflow/sdk/execution_time/secrets_masker.py | 10 ++++------
task-sdk/src/airflow/sdk/execution_time/supervisor.py | 2 +-
6 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/task-sdk/src/airflow/sdk/definitions/_internal/expandinput.py
b/task-sdk/src/airflow/sdk/definitions/_internal/expandinput.py
index 0424380e430..dd341bef1a1 100644
--- a/task-sdk/src/airflow/sdk/definitions/_internal/expandinput.py
+++ b/task-sdk/src/airflow/sdk/definitions/_internal/expandinput.py
@@ -203,11 +203,14 @@ class DictOfListsExpandInput(ResolveMixin):
# TODO: This initiates one API call for each XComArg. Would it be
# more efficient to do one single call and unpack the value here?
+
resolved = {
k: v.resolve(context) if _needs_run_time_resolution(v) else v for
k, v in self.value.items()
}
- all_lengths = self._get_map_lengths(resolved, upstream_map_indexes)
+ sized_resolved = {k: v for k, v in resolved.items() if isinstance(v,
Sized)}
+
+ all_lengths = self._get_map_lengths(sized_resolved,
upstream_map_indexes)
data = {k: self._expand_mapped_field(k, v, map_index, all_lengths) for
k, v in resolved.items()}
literal_keys = {k for k, _ in self._iter_parse_time_resolved_kwargs()}
diff --git a/task-sdk/src/airflow/sdk/definitions/asset/__init__.py
b/task-sdk/src/airflow/sdk/definitions/asset/__init__.py
index 90c972520a0..fae1ec79afe 100644
--- a/task-sdk/src/airflow/sdk/definitions/asset/__init__.py
+++ b/task-sdk/src/airflow/sdk/definitions/asset/__init__.py
@@ -633,7 +633,7 @@ class AssetBooleanCondition(BaseAsset):
class AssetAny(AssetBooleanCondition):
"""Use to combine assets schedule references in an "or" relationship."""
- agg_func = any
+ agg_func = any # type: ignore[assignment]
def __or__(self, other: BaseAsset) -> BaseAsset:
if not isinstance(other, BaseAsset):
@@ -656,7 +656,7 @@ class AssetAny(AssetBooleanCondition):
class AssetAll(AssetBooleanCondition):
"""Use to combine assets schedule references in an "and" relationship."""
- agg_func = all
+ agg_func = all # type: ignore[assignment]
def __and__(self, other: BaseAsset) -> BaseAsset:
if not isinstance(other, BaseAsset):
diff --git a/task-sdk/src/airflow/sdk/definitions/decorators/setup_teardown.py
b/task-sdk/src/airflow/sdk/definitions/decorators/setup_teardown.py
index bcb8e6d12e2..48cb7732494 100644
--- a/task-sdk/src/airflow/sdk/definitions/decorators/setup_teardown.py
+++ b/task-sdk/src/airflow/sdk/definitions/decorators/setup_teardown.py
@@ -18,7 +18,7 @@ from __future__ import annotations
import types
from collections.abc import Callable
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, cast
from airflow.exceptions import AirflowException
from airflow.sdk.bases.operator import BaseOperator
@@ -26,6 +26,7 @@ from airflow.sdk.definitions._internal.setup_teardown import
SetupTeardownContex
from airflow.sdk.definitions.decorators.task_group import _TaskGroupFactory
if TYPE_CHECKING:
+ from airflow.sdk.bases.decorator import _TaskDecorator
from airflow.sdk.definitions.xcom_arg import XComArg
try:
@@ -52,7 +53,8 @@ def setup_task(func: Callable) -> Callable:
func = python_task(func)
if isinstance(func, _TaskGroupFactory):
raise AirflowException("Task groups cannot be marked as setup or
teardown.")
- func.is_setup = True # type: ignore[attr-defined]
+ func = cast("_TaskDecorator", func)
+ func.is_setup = True # type: ignore[attr-defined] # TODO: Remove this
once mypy is bump to 1.16.1
return func
@@ -76,6 +78,9 @@ def teardown_task(_func=None, *, on_failure_fail_dagrun: bool
= False) -> Callab
func = python_task(func)
if isinstance(func, _TaskGroupFactory):
raise AirflowException("Task groups cannot be marked as setup or
teardown.")
+ func = cast("_TaskDecorator", func)
+
+ # TODO: Remove below attr-defined once mypy is bump to 1.16.1
func.is_teardown = True # type: ignore[attr-defined]
func.on_failure_fail_dagrun = on_failure_fail_dagrun # type:
ignore[attr-defined]
return func
diff --git a/task-sdk/src/airflow/sdk/definitions/taskgroup.py
b/task-sdk/src/airflow/sdk/definitions/taskgroup.py
index 6b2c2f65ee4..08db13de7a9 100644
--- a/task-sdk/src/airflow/sdk/definitions/taskgroup.py
+++ b/task-sdk/src/airflow/sdk/definitions/taskgroup.py
@@ -43,6 +43,7 @@ if TYPE_CHECKING:
from airflow.models.expandinput import SchedulerExpandInput
from airflow.sdk.bases.operator import BaseOperator
from airflow.sdk.definitions._internal.abstractoperator import
AbstractOperator
+ from airflow.sdk.definitions._internal.expandinput import
DictOfListsExpandInput, ListOfDictsExpandInput
from airflow.sdk.definitions._internal.mixins import DependencyMixin
from airflow.sdk.definitions.dag import DAG
from airflow.sdk.definitions.edges import EdgeModifier
@@ -613,7 +614,12 @@ class MappedTaskGroup(TaskGroup):
a ``@task_group`` function instead.
"""
- def __init__(self, *, expand_input: SchedulerExpandInput, **kwargs: Any)
-> None:
+ def __init__(
+ self,
+ *,
+ expand_input: SchedulerExpandInput | DictOfListsExpandInput |
ListOfDictsExpandInput,
+ **kwargs: Any,
+ ) -> None:
super().__init__(**kwargs)
self._expand_input = expand_input
diff --git a/task-sdk/src/airflow/sdk/execution_time/secrets_masker.py
b/task-sdk/src/airflow/sdk/execution_time/secrets_masker.py
index 28de9a2afa8..d800f16e615 100644
--- a/task-sdk/src/airflow/sdk/execution_time/secrets_masker.py
+++ b/task-sdk/src/airflow/sdk/execution_time/secrets_masker.py
@@ -27,13 +27,10 @@ from collections.abc import Callable, Generator, Iterable,
Iterator
from enum import Enum
from functools import cache, cached_property
from re import Pattern
-from typing import TYPE_CHECKING, Any, TextIO, TypeAlias, TypeVar
+from typing import Any, TextIO, TypeAlias, TypeVar
from airflow import settings
-if TYPE_CHECKING:
- from typing import TypeGuard
-
V1EnvVar = TypeVar("V1EnvVar")
Redactable: TypeAlias = str | V1EnvVar | dict[Any, Any] | tuple[Any, ...] |
list[Any]
Redacted: TypeAlias = Redactable | str
@@ -154,7 +151,8 @@ def _get_v1_env_var_type() -> type:
return V1EnvVar
-def _is_v1_env_var(v: Any) -> TypeGuard[V1EnvVar]:
+# TODO update return type to TypeGuard[V1EnvVar] once mypy 1.17.0 is available
+def _is_v1_env_var(v: Any) -> bool:
return isinstance(v, _get_v1_env_var_type())
@@ -256,7 +254,7 @@ class SecretsMasker(logging.Filter):
return to_return
if isinstance(item, Enum):
return self._redact(item=item.value, name=name, depth=depth,
max_depth=max_depth)
- if _is_v1_env_var(item):
+ if _is_v1_env_var(item) and hasattr(item, "to_dict"):
tmp: dict = item.to_dict() # type: ignore[attr-defined] #
V1EnvVar has a to_dict method
if should_hide_value_for_key(tmp.get("name", "")) and "value"
in tmp:
tmp["value"] = "***"
diff --git a/task-sdk/src/airflow/sdk/execution_time/supervisor.py
b/task-sdk/src/airflow/sdk/execution_time/supervisor.py
index f5eede6274d..5af102a786c 100644
--- a/task-sdk/src/airflow/sdk/execution_time/supervisor.py
+++ b/task-sdk/src/airflow/sdk/execution_time/supervisor.py
@@ -666,7 +666,7 @@ class WatchedSubprocess:
return
# Escalation sequence: SIGINT -> SIGTERM -> SIGKILL
- escalation_path = [signal.SIGINT, signal.SIGTERM, signal.SIGKILL]
+ escalation_path: list[signal.Signals] = [signal.SIGINT,
signal.SIGTERM, signal.SIGKILL]
if force and signal_to_send in escalation_path:
# Start from `signal_to_send` and escalate to the end of the
escalation path