You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Fix pickling exceptions with multiple arguments #76877
Pickling exceptions fails when a custom exception class requires multiple arguments.
importpickleclassMultipleArgumentsError(Exception):
def__init__(self, a, b):
self.a=aself.b=bpickle.loads(pickle.dumps(MultipleArgumentsError('a', 'b')))
this code produces the following error:
Traceback (most recent call last):
File "/tmp/multiple_arguments_exception.py", line 8, in <module>
pickle.loads(pickle.dumps(MultipleArgumentsError('a', 'b')))
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1388, in loadsreturn Unpickler(file).load()
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 864, in load
dispatch[key](self)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1139, in load_reduce
value = func(*args)
TypeError: __init__() takes exactly 3 arguments (2 given)
The same error occurs when using a built-in module like subprocess:
>>> import subprocess, pickle
>>> try:
... subprocess.check_call(['python', '-c', 'raise SystemExit(1)'])
... exceptExceptionas e:
... pickle.loads(pickle.dumps(e))
...
This isn't really an issue with exceptions, it's just that __reduce__ goes out of sync with the object's constructor signature. Here's a simple example of the same:
Traceback (most recent call last):
File "/Users/iritkatriel/src/cpython/zz.py", line 22, in <module>
z = pickle.loads(y)
^^^^^^^^^^^^^^^TypeError: Derived.__init__() missing 1 required positional argument: 'b'
If I define __reduce__ on Derived to return an arg tuple of the right length for its __init__, it works:
classDerived(Base):
def__init__(self, a, b):
super().__init__(f'{a}|{b}')
def__reduce__(self):
returntype(self), tuple(self.msg.split('|'))
But note that this is not something we could make the base class do, it has no way of finding out what the semantics of the derived class constructor args are.
Activity
slallum commentedon Jan 28, 2018
Pickling exceptions fails when a custom exception class requires multiple arguments.
this code produces the following error:
Related issue: https://bugs.python.org/issue1692335
KirillMatsaberydze commentedon Apr 12, 2018
Hi, I encounter similar behavior in python 3.6.5 with following code:
So it looks like it not only python 2.7 problem
jaraco commentedon Apr 12, 2018
Kirill, see https://bugs.python.org/issue1692335#msg310951 in the related issue for one possible way to work around the issue on Python 3.
iritkatriel commentedon Jun 18, 2021
This is still the same in 3.11:
Cryvate commentedon Jun 18, 2021
It seems like the example in the OP now works (persist both arguments), but Irit's/Kirill's (create a msg) fails (I am running 3.9).
iritkatriel commentedon Jun 27, 2021
See also bpo-43460, bpo-30005, bpo-29466
iritkatriel commentedon Jan 6, 2022
This isn't really an issue with exceptions, it's just that __reduce__ goes out of sync with the object's constructor signature. Here's a simple example of the same:
Output:
If I define __reduce__ on Derived to return an arg tuple of the right length for its __init__, it works:
But note that this is not something we could make the base class do, it has no way of finding out what the semantics of the derived class constructor args are.
youtux commentedon Oct 30, 2022
Should it be documented in the docs how to implement
__reduce__on custom exceptions?