From aabf901c8aa8c4906641c36a556061b6eaded13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Old=C5=99ich=20Jedli=C4=8Dka?= Date: Fri, 3 Nov 2023 11:25:31 +0100 Subject: [PATCH] Deserialize by using __new__ instead of constructor if possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exception to IOError is because this built-in exception is assigning internal myerrno attribute in __init__ constructor and cannot be changed from Python code. Fixes: #65 Signed-off-by: Oldřich Jedlička --- src/tblib/pickling_support.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/tblib/pickling_support.py b/src/tblib/pickling_support.py index 0085140..ea3de51 100644 --- a/src/tblib/pickling_support.py +++ b/src/tblib/pickling_support.py @@ -1,6 +1,6 @@ import copyreg from functools import partial -from types import TracebackType +from types import TracebackType, BuiltinFunctionType from . import Frame from . import Traceback @@ -22,6 +22,19 @@ def pickle_traceback(tb, *, get_locals=None): ) +def unpickle_builtin_exception(func, args, cause, tb, context, suppress_context, notes): + inst = func.__new__(func) + if args is not None: + inst.args = args + inst.__cause__ = cause + inst.__traceback__ = tb + inst.__context__ = context + inst.__suppress_context__ = suppress_context + if notes is not None: + inst.__notes__ = notes + return inst + + # Note: Older versions of tblib will generate pickle archives that call unpickle_exception() with # fewer arguments. We assign default values to some of the arguments to support this. def unpickle_exception(func, args, cause, tb, context=None, suppress_context=False, notes=None): @@ -49,8 +62,12 @@ def pickle_exception(obj): assert isinstance(rv, tuple) assert len(rv) >= 2 + use_builtin = isinstance(obj.__reduce_ex__, BuiltinFunctionType) and \ + isinstance(obj.__reduce__, BuiltinFunctionType) and \ + not isinstance(obj, IOError) + return ( - unpickle_exception, + unpickle_builtin_exception if use_builtin else unpickle_exception, rv[:2] + ( obj.__cause__,