diff --git a/taskflow/types/failure.py b/taskflow/types/failure.py index a0b3a17e..b9d7a399 100644 --- a/taskflow/types/failure.py +++ b/taskflow/types/failure.py @@ -34,6 +34,23 @@ def _copy_exc_info(exc_info): return (exc_type, copy.copy(exc_value), tb) +def _fill_iter(it, desired_len, filler=None): + """Iterates over a provided iterator up to the desired length. + + If the source iterator does not have enough values then the filler + value is yielded until the desired length is reached. + """ + count = 0 + for value in it: + if count >= desired_len: + return + yield value + count += 1 + while count < desired_len: + yield filler + count += 1 + + def _are_equal_exc_info_tuples(ei1, ei2): if ei1 == ei2: return True @@ -274,6 +291,30 @@ class Failure(object): for et in self._exc_type_names: yield et + def __getstate__(self): + dct = self.to_dict() + if self._exc_info: + # Avoids 'TypeError: can't pickle traceback objects' + dct['exc_info'] = self._exc_info[0:2] + return dct + + def __setstate__(self, dct): + self._exception_str = dct['exception_str'] + self._traceback_str = dct['traceback_str'] + self._exc_type_names = dct['exc_type_names'] + if 'exc_info' in dct: + # Tracebacks can't be serialized/deserialized, but since we + # provide a traceback string (and more) this should be + # acceptable... + # + # TODO(harlowja): in the future we could do something like + # what the twisted people have done, see for example + # twisted-13.0.0/twisted/python/failure.py#L89 for how they + # created a fake traceback object... + self._exc_info = tuple(_fill_iter(dct['exc_info'], 3)) + else: + self._exc_info = None + @classmethod def from_dict(cls, data): """Converts this from a dictionary to a object."""