You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by bb...@apache.org on 2025/03/26 00:35:03 UTC

(airflow) branch main updated: Minor cleanup on grid endpoint (#48371)

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

bbovenzi 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 ab05274c93d Minor cleanup on grid endpoint (#48371)
ab05274c93d is described below

commit ab05274c93d857271bf7dbdb6d2c70afbeca83cf
Author: Jed Cunningham <66...@users.noreply.github.com>
AuthorDate: Tue Mar 25 18:34:56 2025 -0600

    Minor cleanup on grid endpoint (#48371)
    
    This just cleans up some code in the grid endpoint - no real changes.
    
    - this uses a proper config enum for the grid view sort order config -
      fails at startup, not throwing a 500 in responses
    - removes unnecessary fallback
    - count child nodes directly - no need to sort then iterate through then
      count
    - simplifies some other code too
---
 .../airflow/api_fastapi/core_api/routes/ui/grid.py |  6 ++--
 .../api_fastapi/core_api/services/ui/grid.py       | 34 ++++++++++------------
 airflow-core/src/airflow/configuration.py          |  1 +
 3 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py
index d21c367251e..78453a10c96 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py
@@ -186,7 +186,7 @@ def grid_data(
     )
     # Create the Task Instance Summaries to be used in the Grid Response
     task_instance_summaries: dict[str, list] = {
-        run_id: [] for (_, run_id), _ in itertools.chain(parent_tis.items(), all_tis.items())
+        run_id: [] for _, run_id in itertools.chain(parent_tis, all_tis)
     }
 
     # Fill the Task Instance Summaries for the Parent and Grouped Task Instances.
@@ -220,9 +220,7 @@ def grid_data(
             data_interval_end=dag_run.data_interval_end,
             version_number=dag_run.version_number,
             note=dag_run.note,
-            task_instances=(
-                task_instance_summaries[dag_run.run_id] if dag_run.run_id in task_instance_summaries else []
-            ),
+            task_instances=task_instance_summaries.get(dag_run.run_id, []),
         )
         for dag_run in dag_runs
     ]
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py b/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py
index 74c44318a5a..61f84f33e0d 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py
@@ -17,8 +17,9 @@
 
 from __future__ import annotations
 
-import operator
 from functools import cache
+from operator import methodcaller
+from typing import Callable
 
 from typing_extensions import Any
 
@@ -31,7 +32,6 @@ from airflow.api_fastapi.core_api.datamodels.ui.grid import (
     GridTaskInstanceSummary,
 )
 from airflow.configuration import conf
-from airflow.exceptions import AirflowConfigException
 from airflow.models.baseoperator import BaseOperator as DBBaseOperator
 from airflow.models.taskmap import TaskMap
 from airflow.sdk import BaseOperator
@@ -41,14 +41,12 @@ from airflow.utils.state import TaskInstanceState
 
 
 @cache
-def get_task_group_children_getter() -> operator.methodcaller:
+def get_task_group_children_getter() -> Callable:
     """Get the Task Group Children Getter for the DAG."""
-    sort_order = conf.get("webserver", "grid_view_sorting_order", fallback="topological")
+    sort_order = conf.get("webserver", "grid_view_sorting_order")
     if sort_order == "topological":
-        return operator.methodcaller("topological_sort")
-    if sort_order == "hierarchical_alphabetical":
-        return operator.methodcaller("hierarchical_alphabetical_sort")
-    raise AirflowConfigException(f"Unsupported grid_view_sorting_order: {sort_order}")
+        return methodcaller("topological_sort")
+    return methodcaller("hierarchical_alphabetical_sort")
 
 
 def get_task_group_map(dag: DAG) -> dict[str, dict[str, Any]]:
@@ -83,10 +81,11 @@ def get_task_group_map(dag: DAG) -> dict[str, dict[str, Any]]:
     def _fill_task_group_map(
         task_node: BaseOperator | MappedTaskGroup | TaskMap | None,
         parent_node: BaseOperator | MappedTaskGroup | TaskMap | None,
-    ):
+    ) -> None:
         """Recursively fill the Task Group Map."""
         if task_node is None:
             return
+
         if isinstance(task_node, MappedOperator):
             task_nodes[task_node.node_id] = {
                 "is_group": False,
@@ -96,22 +95,19 @@ def get_task_group_map(dag: DAG) -> dict[str, dict[str, Any]]:
             # Add the Task Count to the Parent Node because parent node is a Task Group
             _append_child_task_count_to_parent(child_task_count=task_node, parent_node=parent_node)
             return
-        elif isinstance(task_node, TaskGroup):
-            task_count = (
-                task_node
-                if _is_task_node_mapped_task_group(task_node)
-                else len([child for child in get_task_group_children_getter()(task_node)])
-            )
+
+        if isinstance(task_node, TaskGroup):
+            task_count = task_node if _is_task_node_mapped_task_group(task_node) else len(task_node.children)
             task_nodes[task_node.node_id] = {
                 "is_group": True,
                 "parent_id": parent_node.node_id if parent_node else None,
                 "task_count": [task_count],
             }
-            return [
+            for child in get_task_group_children_getter()(task_node):
                 _fill_task_group_map(task_node=child, parent_node=task_node)
-                for child in get_task_group_children_getter()(task_node)
-            ]
-        elif isinstance(task_node, BaseOperator):
+            return
+
+        if isinstance(task_node, BaseOperator):
             task_nodes[task_node.task_id] = {
                 "is_group": False,
                 "parent_id": parent_node.node_id if parent_node else None,
diff --git a/airflow-core/src/airflow/configuration.py b/airflow-core/src/airflow/configuration.py
index 7b57ef93f01..5104317b90c 100644
--- a/airflow-core/src/airflow/configuration.py
+++ b/airflow-core/src/airflow/configuration.py
@@ -381,6 +381,7 @@ class AirflowConfigParser(ConfigParser):
         # celery_logging_level can be empty, which uses logging_level as fallback
         ("logging", "celery_logging_level"): [*_available_logging_levels, ""],
         ("webserver", "analytical_tool"): ["google_analytics", "metarouter", "segment", "matomo", ""],
+        ("webserver", "grid_view_sorting_order"): ["topological", "hierarchical_alphabetical"],
     }
 
     upgraded_values: dict[tuple[str, str], str]