Skip to content

Commit

Permalink
Deserialize by using __new__ instead of constructor if possible
Browse files Browse the repository at this point in the history
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: ionelmc#65

Signed-off-by: Oldřich Jedlička <oldium.pro@gmail.com>
  • Loading branch information
oldium committed Nov 3, 2023
1 parent 1e5a2e6 commit aabf901
Showing 1 changed file with 19 additions and 2 deletions.
21 changes: 19 additions & 2 deletions src/tblib/pickling_support.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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__,
Expand Down

0 comments on commit aabf901

Please sign in to comment.