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.
if op.params:  
                    v, new = op.params, v
                    v.update(new)
            elif k == "partial_kwargs":
                v = {arg: cls.deserialize(value) for arg, value in v.items()}
            elif k in {"expand_input", "op_kwargs_expand_input"}:
                v = _ExpandInputRef(v["type"], cls.deserialize(v["value"]))
            elif (
                k in cls._decorated_fields
                or k not in op.get_serialized_fields()
                or k in ("outlets", "inlets")
            ):
                v = cls.deserialize(v)
            elif k == "on_failure_fail_dagrun":
                k = "_on_failure_fail_dagrun"
            
            setattr(op, k, v)
        for k in op.get_serialized_fields() - encoded_op.keys() - cls._CONSTRUCTOR_PARAMS.keys():
            
            
            if not hasattr(op, k):
                setattr(op, k, None)
        
        for field in op.template_fields:
            if not hasattr(op, field):
                setattr(op, field, None)
        
        setattr(op, "_is_empty", bool(encoded_op.get("_is_empty", False)))
    @staticmethod
    def set_task_dag_references(task: Operator, dag: DAG) -> None: