This is an automated email from the ASF dual-hosted git repository.

ash 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 7ea624535b8 Re-introduce TypeGuard to SecretsMasker (#54055)
7ea624535b8 is described below

commit 7ea624535b8fdf85706e5b4ae742192077d73e43
Author: Ash Berlin-Taylor <[email protected]>
AuthorDate: Sat Aug 2 22:19:00 2025 +0100

    Re-introduce TypeGuard to SecretsMasker (#54055)
    
    We've upraded to MyPy 1.17.0 now, so we can use the type guard again.
    
    Also remove the redundant hasattr check - it was only needed because of
    incorrect mocking in tests.
---
 .../src/airflow/sdk/execution_time/secrets_masker.py  | 19 +++++++++++++------
 .../tests/task_sdk/definitions/test_secrets_masker.py |  5 ++++-
 2 files changed, 17 insertions(+), 7 deletions(-)

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 ae8c8e617ae..04f2c0e8e82 100644
--- a/task-sdk/src/airflow/sdk/execution_time/secrets_masker.py
+++ b/task-sdk/src/airflow/sdk/execution_time/secrets_masker.py
@@ -27,10 +27,17 @@ 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 Any, TextIO, TypeAlias, TypeVar, overload
+from typing import TYPE_CHECKING, Any, Protocol, TextIO, TypeAlias, TypeVar, 
overload
 
 from airflow import settings
 
+if TYPE_CHECKING:
+    from typing import TypeGuard
+
+    class _V1EnvVarLike(Protocol):
+        def to_dict(self) -> dict[str, Any]: ...
+
+
 V1EnvVar = TypeVar("V1EnvVar")
 Redactable: TypeAlias = str | V1EnvVar | dict[Any, Any] | tuple[Any, ...] | 
list[Any]
 Redacted: TypeAlias = Redactable | str
@@ -167,13 +174,13 @@ def reset_secrets_masker() -> None:
 def _get_v1_env_var_type() -> type:
     try:
         from kubernetes.client import V1EnvVar
+
+        return V1EnvVar
     except ImportError:
         return type("V1EnvVar", (), {})
-    return V1EnvVar
 
 
-# TODO update return type to TypeGuard[V1EnvVar] once mypy 1.17.0 is available
-def _is_v1_env_var(v: Any) -> bool:
+def _is_v1_env_var(v: Any) -> TypeGuard[_V1EnvVarLike]:
     return isinstance(v, _get_v1_env_var_type())
 
 
@@ -275,8 +282,8 @@ 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) and hasattr(item, "to_dict"):
-                tmp: dict = item.to_dict()
+            if _is_v1_env_var(item):
+                tmp = item.to_dict()
                 if should_hide_value_for_key(tmp.get("name", "")) and "value" 
in tmp:
                     tmp["value"] = "***"
                 else:
diff --git a/task-sdk/tests/task_sdk/definitions/test_secrets_masker.py 
b/task-sdk/tests/task_sdk/definitions/test_secrets_masker.py
index 4d3c3e7d576..2e95d60b943 100644
--- a/task-sdk/tests/task_sdk/definitions/test_secrets_masker.py
+++ b/task-sdk/tests/task_sdk/definitions/test_secrets_masker.py
@@ -609,7 +609,10 @@ class TestContainerTypesRedaction:
         secrets_masker = SecretsMasker()
 
         with 
patch("airflow.sdk.execution_time.secrets_masker._secrets_masker", 
return_value=secrets_masker):
-            with 
patch("airflow.sdk.execution_time.secrets_masker._is_v1_env_var", 
return_value=True):
+            with patch(
+                "airflow.sdk.execution_time.secrets_masker._is_v1_env_var",
+                side_effect=lambda a: isinstance(a, MockV1EnvVar),
+            ):
                 redacted_secret = redact(secret_env_var)
                 redacted_normal = redact(normal_env_var)
 

Reply via email to