Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9ac0d6a
fixed the label selector for none values
Vasu-Madaan Jul 17, 2025
0dcb441
Merge branch 'main' into main
Vasu-Madaan Jul 17, 2025
fa93c89
correcting the formation
Vasu-Madaan Jul 18, 2025
f5bec52
Merge branch 'main' of https://github.com/Vasu-Madaan/airflow
Vasu-Madaan Jul 18, 2025
78880bd
Merge branch 'apache:main' into main
Vasu-Madaan Jul 18, 2025
49ce7b7
reformatting as per RUFF
Vasu-Madaan Jul 18, 2025
daee39e
Merge branch 'main' of https://github.com/Vasu-Madaan/airflow
Vasu-Madaan Jul 18, 2025
23c1fea
Merge branch 'apache:main' into main
Vasu-Madaan Aug 9, 2025
2892981
Merge branch 'apache:main' into main
Vasu-Madaan Sep 24, 2025
5e345b9
Merge branch 'apache:main' into main
Vasu-Madaan Sep 24, 2025
cbc053b
Add normalize_labels_dict(labels: dict) helper to replace None with "…
Vasu-Madaan Sep 24, 2025
1a15682
Merge branch 'main' into main
Vasu-Madaan Sep 24, 2025
2715125
Test cases have been added
Vasu-Madaan Sep 24, 2025
f5a5ad6
Merge branch 'apache:main' into main
Vasu-Madaan Sep 24, 2025
1322ee1
Merge branch 'main' of https://github.com/Vasu-Madaan/airflow
Vasu-Madaan Sep 24, 2025
1b0d592
Update providers/cncf/kubernetes/src/airflow/providers/cncf/kubernete…
eladkal Sep 25, 2025
cf05baf
Merge branch 'apache:main' into main
Vasu-Madaan Sep 25, 2025
deda7d0
Merge branch 'apache:main' into main
Vasu-Madaan Sep 25, 2025
58b92ca
Ruff formated pod.py
Vasu-Madaan Sep 25, 2025
c90750d
Merge branch 'apache:main' into main
Vasu-Madaan Oct 23, 2025
2d98607
Changes added as per the suhhestions from Amogh
Vasu-Madaan Oct 23, 2025
5e3b802
Combined the test cases with "pytest.parameterize" for "_normalize_la…
Vasu-Madaan Oct 23, 2025
0d3d68f
Test case added for "_build_find_pod_label_selector" for all values p…
Vasu-Madaan Oct 23, 2025
4e7d4ff
Ruff formated
Vasu-Madaan Oct 23, 2025
11239b0
removed the additional test case
Vasu-Madaan Oct 23, 2025
c22c7a2
checks added on pod creation as well
Vasu-Madaan Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,7 @@ def _build_find_pod_label_selector(self, context: Context | None = None, *, excl
**self.labels,
**self._get_ti_pod_labels(context, include_try_number=False),
}
labels = _normalize_labels_dict(labels)
label_strings = [f"{label_id}={label}" for label_id, label in sorted(labels.items())]
labels_value = ",".join(label_strings)
if exclude_checked:
Expand Down Expand Up @@ -1280,7 +1281,7 @@ def build_pod_request_obj(self, context: Context | None = None) -> k8s.V1Pod:
kind="Pod",
metadata=k8s.V1ObjectMeta(
namespace=self.namespace,
labels=self.labels,
labels=_normalize_labels_dict(self.labels),
name=self.name,
annotations=self.annotations,
),
Expand Down Expand Up @@ -1437,3 +1438,8 @@ def __exit__(self, exctype, excinst, exctb) -> bool:
logger = logging.getLogger(__name__)
logger.exception(excinst)
return True


def _normalize_labels_dict(labels: dict) -> dict:
"""Return a copy of the labels dict with all None values replaced by empty strings."""
return {k: ("" if v is None else v) for k, v in labels.items()}
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ def test_labels(self, hook_mock, in_cluster):
namespace="default",
image="ubuntu:16.04",
cmds=["bash", "-cx"],
labels={"foo": "bar"},
labels={"foo": "bar", "none_value": None},
name="test",
task_id="task",
in_cluster=in_cluster,
Expand All @@ -424,6 +424,7 @@ def test_labels(self, hook_mock, in_cluster):
"airflow_version": mock.ANY,
"run_id": "test",
"airflow_kpo_in_cluster": str(in_cluster),
"none_value": "", # None converted to empty string
}

def test_labels_mapped(self):
Expand Down Expand Up @@ -454,6 +455,49 @@ def test_find_custom_pod_labels(self):
assert "foo=bar" in label_selector
assert "hello=airflow" in label_selector

def test_build_find_pod_label_selector(self):
"""Comprehensive single test combining all label normalization scenarios.

Includes: normal labels, None values, empty string, zero, False.
Asserts: None -> empty assignment, other falsy preserved, core airflow labels present, no literal 'None'.
"""
k = KubernetesPodOperator(
labels={
"foo": "bar",
"hello": "airflow",
"a": None,
"c": None,
"empty_str": "",
"zero": 0,
"false": False,
"none": None,
},
name="test",
task_id="task",
)
context = create_context(k)
label_selector = k._build_find_pod_label_selector(context)

# Standard labels
assert "foo=bar" in label_selector
assert "hello=airflow" in label_selector

# None normalization (shows as key= with no value)
for key in ["a", "c", "none"]:
assert f"{key}=" in label_selector

# Falsy but non-None values preserved verbatim
assert "empty_str=" in label_selector
assert "zero=0" in label_selector
assert "false=False" in label_selector

# Core Airflow identifying labels always present
for core in ["dag_id=dag", "task_id=task", "kubernetes_pod_operator=True", "run_id=test"]:
assert core in label_selector

# Never include literal string 'None'
assert "None" not in label_selector

@pytest.mark.asyncio
@patch(HOOK_CLASS, new=MagicMock)
def test_find_pod_labels(self):
Expand Down Expand Up @@ -1656,6 +1700,27 @@ def test_task_id_as_name_dag_id_is_ignored(self):
pod = k.build_pod_request_obj({})
assert re.match(r"a-very-reasonable-task-name-[a-z0-9-]+", pod.metadata.name) is not None

@pytest.mark.parametrize(
"labels,expected",
[
pytest.param({}, {}, id="empty"),
pytest.param(
{"a": None, "b": "value", "c": None}, {"a": "", "b": "value", "c": ""}, id="with-none"
),
pytest.param(
{"empty_str": "", "zero": 0, "false": False, "none": None},
{"empty_str": "", "zero": 0, "false": False, "none": ""},
id="preserve-other-values",
),
],
)
def test_normalize_labels_dict(self, labels, expected):
"""normalize_labels_dict should transform only None values to empty strings and preserve others"""
from airflow.providers.cncf.kubernetes.operators.pod import _normalize_labels_dict

normalized = _normalize_labels_dict(labels)
assert normalized == expected

@patch(f"{POD_MANAGER_CLASS}.extract_xcom")
@patch(f"{POD_MANAGER_CLASS}.await_xcom_sidecar_container_start")
@patch(f"{POD_MANAGER_CLASS}.await_pod_completion")
Expand Down