diff --git a/tools/exekall/exekall/_utils.py b/tools/exekall/exekall/_utils.py index dcb6e89678b23a8fdf7ff88699d633eeccfe2569..a805f087ed514d113451b76d2a148f228eca672f 100644 --- a/tools/exekall/exekall/_utils.py +++ b/tools/exekall/exekall/_utils.py @@ -253,8 +253,12 @@ class ExceptionPickler(pickle.Pickler): raise KeyError def __init__(self, *args, **kwargs): - self.dispatch_table = self._DispatchTable(self) + + # Due to this issue, it is critical that "dispatch_table" is set after + # calling super().__init__ + # https://bugs.python.org/issue45830 super().__init__(*args, **kwargs) + self.dispatch_table = self._DispatchTable(self) @staticmethod def _make_excep(excep_cls, dct): @@ -314,25 +318,30 @@ class ExceptionPickler(pickle.Pickler): pickler = cls(f, **kwargs) return pickler.dump(obj) + @classmethod + def is_serializable(cls, obj, raise_excep=False): + """ + Try to Pickle the object to see if that raises any exception. + """ + class DevNull: + def write(self, _): + pass + try: + # This may be slow for big objects but it is the only way to be + # sure it can actually be serialized + cls.dump_file(DevNull(), obj) + except (TypeError, pickle.PickleError, AttributeError) as e: + debug('Cannot serialize instance of {}: {}'.format( + type(obj).__qualname__, str(e) + )) + if raise_excep: + raise NotSerializableError(obj) from e + return False + else: + return True + -def is_serializable(obj, raise_excep=False): - """ - Try to Pickle the object to see if that raises any exception. - """ - stream = io.StringIO() - try: - # This may be slow for big objects but it is the only way to be sure - # it can actually be serialized - ExceptionPickler.dump_bytestring(obj) - except (TypeError, pickle.PickleError, AttributeError) as e: - debug('Cannot serialize instance of {}: {}'.format( - type(obj).__qualname__, str(e) - )) - if raise_excep: - raise NotSerializableError(obj) from e - return False - else: - return True +is_serializable = ExceptionPickler.is_serializable def once(callable_):