Cattrs is currently only used in two places: Serialization for operator extra links, and for Lineage.

However cattrs is not a well maintained project and doesn't support many features that attrs itself does; in short, it's not worth the brain cycles to keep cattrs.
"""Serialize TaskGroup into a JSON object."""
        if not task_group:
            return None
        
        
        
        encoded = {
            "_group_id": task_group._group_id,
            "prefix_group_id": task_group.prefix_group_id,
            "tooltip": task_group.tooltip,
            "ui_color": task_group.ui_color,
            "ui_fgcolor": task_group.ui_fgcolor,
            "children": {
                label: child.serialize_for_task_group() for label, child in task_group.children.items()
            },
            "upstream_group_ids": cls.serialize(sorted(task_group.upstream_group_ids)),
            "downstream_group_ids": cls.serialize(sorted(task_group.downstream_group_ids)),
            "upstream_task_ids": cls.serialize(sorted(task_group.upstream_task_ids)),
            "downstream_task_ids": cls.serialize(sorted(task_group.downstream_task_ids)),
        }
        if isinstance(task_group, MappedTaskGroup):
            expand_input = task_group._expand_input
            encoded["expand_input"] = {
                "type": get_map_type_key(expand_input),
                "value": cls.serialize(expand_input.value),
            }
            encoded["is_mapped"] = True
        return encoded
    @classmethod
    def deserialize_task_group(