import pickle
import warnings
import weakref


class AutoPickle:
    """
    Module to automatically ignore un-pickle-able objects
    """

    def __getstate__(self):
        state = {}
        warned_attrs = getattr(self, "_warned_attrs", set())

        # ✅ Iterate over a COPY of self.__dict__.items() to avoid runtime errors
        for key, value in list(self.__dict__.items()):
            try:
                # ✅ Prevent circular references (self-referencing attributes)
                if isinstance(value, (weakref.ReferenceType, type(self))):
                    continue  # Ignore self-references

                # ✅ Try pickling the attribute
                pickle.dumps(value)
                state[key] = value  # Keep if it's pickleable

            except (pickle.PicklingError, TypeError, AttributeError, RecursionError):
                # ✅ Warn about unpickleable attributes only ONCE
                if key not in warned_attrs:
                    warnings.warn(
                        f"[{self.__class__.__name__}]: Can't pickle '{key}', skipping.")
                    warned_attrs.add(key)

                state[key] = None  # Replace unpickleable attributes with None

        # Save warned attributes to avoid duplicate warnings
        self._warned_attrs = warned_attrs
        return state

    def __setstate__(self, state):
        self.__dict__.update(state)
