diff --git a/airflow/decorators/task_group.py b/airflow/decorators/task_group.py index 591ba39018e1d..2fabd29157ddc 100644 --- a/airflow/decorators/task_group.py +++ b/airflow/decorators/task_group.py @@ -189,6 +189,7 @@ def task_group( ui_color: str = "CornflowerBlue", ui_fgcolor: str = "#000", add_suffix_on_collision: bool = False, + group_display_name: str = "", ) -> Callable[[Callable[FParams, FReturn]], _TaskGroupFactory[FParams, FReturn]]: ... diff --git a/airflow/serialization/schema.json b/airflow/serialization/schema.json index 1cc9c42db0737..4eaae95ba2b01 100644 --- a/airflow/serialization/schema.json +++ b/airflow/serialization/schema.json @@ -310,6 +310,7 @@ "type": "object", "required": [ "_group_id", + "group_display_name", "prefix_group_id", "children", "tooltip", @@ -322,6 +323,7 @@ ], "properties": { "_group_id": {"anyOf": [{"type": "null"}, { "type": "string" }]}, + "group_display_name": {"type": "string" }, "is_mapped": { "type": "boolean" }, "prefix_group_id": { "type": "boolean" }, "children": { "$ref": "#/definitions/dict" }, diff --git a/airflow/serialization/serialized_objects.py b/airflow/serialization/serialized_objects.py index 3263f3dc5c320..a0e5da74145cf 100644 --- a/airflow/serialization/serialized_objects.py +++ b/airflow/serialization/serialized_objects.py @@ -1787,6 +1787,7 @@ def serialize_task_group(cls, task_group: TaskGroup) -> dict[str, Any] | None: # When calling json.dumps(self.data, sort_keys=True) to generate dag_hash, misjudgment will occur encoded = { "_group_id": task_group._group_id, + "group_display_name": task_group.group_display_name, "prefix_group_id": task_group.prefix_group_id, "tooltip": task_group.tooltip, "ui_color": task_group.ui_color, @@ -1822,7 +1823,7 @@ def deserialize_task_group( group_id = cls.deserialize(encoded_group["_group_id"]) kwargs = { key: cls.deserialize(encoded_group[key]) - for key in ["prefix_group_id", "tooltip", "ui_color", "ui_fgcolor"] + for key in ["prefix_group_id", "tooltip", "ui_color", "ui_fgcolor", "group_display_name"] } if not encoded_group.get("is_mapped"): diff --git a/task_sdk/src/airflow/sdk/definitions/taskgroup.py b/task_sdk/src/airflow/sdk/definitions/taskgroup.py index 52b30ba31f8af..07f8b452c1954 100644 --- a/task_sdk/src/airflow/sdk/definitions/taskgroup.py +++ b/task_sdk/src/airflow/sdk/definitions/taskgroup.py @@ -101,11 +101,13 @@ class TaskGroup(DAGNode): :param ui_fgcolor: The label color of the TaskGroup node when displayed in the UI :param add_suffix_on_collision: If this task group name already exists, automatically add `__1` etc suffixes + :param group_display_name: If set, this will be the display name for the TaskGroup node in the UI. """ _group_id: str | None = attrs.field( validator=attrs.validators.optional(attrs.validators.instance_of(str)) ) + group_display_name: str = attrs.field(default="", validator=attrs.validators.instance_of(str)) prefix_group_id: bool = attrs.field(default=True) parent_group: TaskGroup | None = attrs.field(factory=_default_parent_group) dag: DAG = attrs.field(default=attrs.Factory(_default_dag, takes_self=True)) @@ -270,7 +272,7 @@ def group_id(self) -> str | None: @property def label(self) -> str | None: """group_id excluding parent's group_id used as the node label in UI.""" - return self._group_id + return self.group_display_name or self._group_id def update_relative( self,