# Buggy code
def __setitem__(self, key, value):
    """ """
    # keys which need to refresh derived values
    if key in ["delta", "sampling_rate", "starttime", "npts"]:
        # ensure correct data type
        if key == "delta":
            key = "sampling_rate"
            value = 1.0 / float(value)
        elif key == "sampling_rate":
            value = float(value)
        elif key == "starttime":
            value = UTCDateTime(value)
        elif key == "npts":
            if not isinstance(value, int):
                value = int(value)
        # set current key
        super(Stats, self).__setitem__(key, value)
        # set derived value: delta
        try:
            delta = 1.0 / float(self.sampling_rate)
        except ZeroDivisionError:
            delta = 0
        self.__dict__["delta"] = delta
        # set derived value: endtime
        if self.npts == 0:
            timediff = 0
        else:
            timediff = float(self.npts - 1) * delta
        self.__dict__["endtime"] = self.starttime + timediff
        return
    # prevent a calibration factor of 0
    if key == "calib" and value == 0:
        msg = "Calibration factor set to 0.0!"
        warnings.warn(msg, UserWarning)
    # all other keys
    if isinstance(value, dict):
        super(Stats, self).__setitem__(key, AttribDict(value))
    else:
        super(Stats, self).__setitem__(key, value)


# Traceback (ZeroDivisionError)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-7-c105e6dd98fb> in <module>()
----> 1 pickle.loads(pickle.dumps(t))

~/code/obspy/obspy/core/util/attribdict.py in __setstate__(self, adict)
113         self.__dict__.update(self.defaults)
114         # update with pickle dictionary
--> 115         self.update(adict)
116
117     def __getattr__(self, name, default=None):

~/code/obspy/obspy/core/util/attribdict.py in update(self, adict)
140             if key in self.readonly:
141                 continue
--> 142             self.__setitem__(key, value)
143
144     def _pretty_str(self, priorized_keys=[], min_label_length=16):

~/code/obspy/obspy/core/trace.py in __setitem__(self, key, value)
159             if key == 'delta':
160                 key = 'sampling_rate'
--> 161                 value = 1.0 / float(value)
162             elif key == 'sampling_rate':
163                 value = float(value)

ZeroDivisionError: float division by zero

# Fixed code
def __setitem__(self, key, value):
    """ """
    # keys which need to refresh derived values
    if key in ["delta", "sampling_rate", "starttime", "npts"]:
        # ensure correct data type
        if key == "delta":
            key = "sampling_rate"
            try:
                value = 1.0 / float(value)
            except ZeroDivisionError:
                value = 0.0
        elif key == "sampling_rate":
            value = float(value)
        elif key == "starttime":
            value = UTCDateTime(value)
        elif key == "npts":
            if not isinstance(value, int):
                value = int(value)
        # set current key
        super(Stats, self).__setitem__(key, value)
        # set derived value: delta
        try:
            delta = 1.0 / float(self.sampling_rate)
        except ZeroDivisionError:
            delta = 0
        self.__dict__["delta"] = delta
        # set derived value: endtime
        if self.npts == 0:
            timediff = 0
        else:
            timediff = float(self.npts - 1) * delta
        self.__dict__["endtime"] = self.starttime + timediff
        return
    # prevent a calibration factor of 0
    if key == "calib" and value == 0:
        msg = "Calibration factor set to 0.0!"
        warnings.warn(msg, UserWarning)
    # all other keys
    if isinstance(value, dict):
        super(Stats, self).__setitem__(key, AttribDict(value))
    else:
        super(Stats, self).__setitem__(key, value)