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

pierrejeambrun pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-0-test by this push:
     new ebbe3b79e22 [v3-0-test] Fix Task Instance “No Status” Filter (#51880) 
(#52154)
ebbe3b79e22 is described below

commit ebbe3b79e227d60885bba7adc87652ebcc7850b7
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Jun 24 15:23:09 2025 +0200

    [v3-0-test] Fix Task Instance “No Status” Filter (#51880) (#52154)
    
    * Support no_status alias in TaskInstance state filter for REST API
    
    * Allow 'no_status' state filter and include no_status in valid state list; 
skip date filters when filtering for null state
    
    * Fix NULL-state filtering in get_mapped_task_instances by coalescing date 
fields
    
    * Refactor datetime_range_filter_factory: coalesce only start_date and 
end_date filters
    
    * Add a test
    (cherry picked from commit c71566b888b7aa48048649feccc4bed9bbf8b02a)
    
    Co-authored-by: Ankit Chaurasia <[email protected]>
---
 .../src/airflow/api_fastapi/common/parameters.py    |  9 ++++++---
 .../core_api/routes/public/test_task_instances.py   | 21 +++++++++++++++++++++
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/airflow-core/src/airflow/api_fastapi/common/parameters.py 
b/airflow-core/src/airflow/api_fastapi/common/parameters.py
index 141447488c2..4219bb66284 100644
--- a/airflow-core/src/airflow/api_fastapi/common/parameters.py
+++ b/airflow-core/src/airflow/api_fastapi/common/parameters.py
@@ -37,7 +37,7 @@ from typing import (
 from fastapi import Depends, HTTPException, Query, status
 from pendulum.parsing.exceptions import ParserError
 from pydantic import AfterValidator, BaseModel, NonNegativeInt
-from sqlalchemy import Column, and_, case, or_
+from sqlalchemy import Column, and_, case, func, or_
 from sqlalchemy.inspection import inspect
 
 from airflow.api_fastapi.core_api.base import OrmClause
@@ -484,9 +484,12 @@ def datetime_range_filter_factory(
         lower_bound: datetime | None = Query(alias=f"{filter_name}_gte", 
default=None),
         upper_bound: datetime | None = Query(alias=f"{filter_name}_lte", 
default=None),
     ) -> RangeFilter:
+        attr = getattr(model, attribute_name or filter_name)
+        if filter_name in ("start_date", "end_date"):
+            attr = func.coalesce(attr, func.now())
         return RangeFilter(
             Range(lower_bound=lower_bound, upper_bound=upper_bound),
-            getattr(model, attribute_name or filter_name),
+            attr,
         )
 
     return depends_datetime
@@ -601,7 +604,7 @@ def _transform_ti_states(states: list[str] | None) -> 
list[TaskInstanceState | N
         return None
 
     try:
-        return [None if s in ("none", None) else TaskInstanceState(s) for s in 
states]
+        return [None if s in ("no_status", "none", None) else 
TaskInstanceState(s) for s in states]
     except ValueError:
         raise HTTPException(
             status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
index 49769007fa8..c0cdffd56b3 100644
--- 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
+++ 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
@@ -956,6 +956,19 @@ class TestGetTaskInstances(TestTaskInstanceEndpoint):
                 3,
                 id="test state filter",
             ),
+            pytest.param(
+                [
+                    {"state": State.RUNNING},
+                    {"state": State.QUEUED},
+                    {"state": State.SUCCESS},
+                    {"state": State.NONE},
+                ],
+                False,
+                
("/dags/example_python_operator/dagRuns/TEST_DAG_RUN_ID/taskInstances"),
+                {"state": ["no_status"]},
+                1,
+                id="test no_status state filter",
+            ),
             pytest.param(
                 [
                     {"state": State.NONE},
@@ -969,6 +982,14 @@ class TestGetTaskInstances(TestTaskInstanceEndpoint):
                 4,
                 id="test null states with no filter",
             ),
+            pytest.param(
+                [{"start_date": None, "end_date": None}],
+                True,
+                
"/dags/example_python_operator/dagRuns/TEST_DAG_RUN_ID/taskInstances",
+                {"start_date_gte": DEFAULT_DATETIME_STR_1},
+                1,
+                id="test start_date coalesce with null",
+            ),
             pytest.param(
                 [
                     {"pool": "test_pool_1"},

Reply via email to