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.
v = cls.deserialize(v)
            
            setattr(dag, k, v)
        
        
        
        if "timetable" in encoded_dag:
            dag.schedule_interval = dag.timetable.summary
        else:
            dag.timetable = create_timetable(dag.schedule_interval, dag.timezone)
        
        if "_task_group" in encoded_dag:
            dag._task_group = TaskGroupSerialization.deserialize_task_group(
                encoded_dag["_task_group"],
                None,
                dag.task_dict,
                dag,
            )
        else:
            
            
            dag._task_group = TaskGroup.create_root(dag)
            for task in dag.tasks:
                dag.task_group.add(task)
        
        if "has_on_success_callback" in encoded_dag:
            dag.has_on_success_callback = True
        if "has_on_failure_callback" in encoded_dag:
            dag.has_on_failure_callback = True
        keys_to_set_none = dag.get_serialized_fields() - encoded_dag.keys() - cls._CONSTRUCTOR_PARAMS.keys()