Issue 32696: Fix pickling exceptions with multiple arguments
Created on 2018-01-28 16:15 by slallum, last changed 2022-04-11 14:58 by admin. This issue is now closed.
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 30602 | closed | Zefir-13000, 2022-01-14 16:49 | |
| Messages (7) | |||
|---|---|---|---|
| msg310963 - (view) | Author: Ofer (slallum) | Date: 2018-01-28 16:15 | |
Pickling exceptions fails when a custom exception class requires multiple arguments.
import pickle
class MultipleArgumentsError(Exception):
def __init__(self, a, b):
self.a = a
self.b = b
pickle.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 loads
return 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)'])
... except Exception as e:
... pickle.loads(pickle.dumps(e))
...
Related issue: https://bugs.python.org/issue1692335
|
|||
| msg315225 - (view) | Author: Kirill Matsaberydze (Kirill Matsaberydze) | Date: 2018-04-12 15:07 | |
Hi, I encounter similar behavior in python 3.6.5 with following code:
import pickle
class CustomException(Exception):
def __init__(self, arg1, arg2):
msg = "Custom message {} {}".format(arg1, arg2)
super().__init__(msg)
obj_dump = pickle.dumps(CustomException("arg1", "arg2"))
obj = pickle.loads(obj_dump)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() missing 1 required positional argument: 'arg2'
So it looks like it not only python 2.7 problem
|
|||
| msg315230 - (view) | Author: Jason R. Coombs (jaraco) * ![]() |
Date: 2018-04-12 16:42 | |
Kirill, see https://bugs.python.org/issue1692335#msg310951 in the related issue for one possible way to work around the issue on Python 3. |
|||
| msg396035 - (view) | Author: Irit Katriel (iritkatriel) * ![]() |
Date: 2021-06-18 08:41 | |
This is still the same in 3.11:
>>> import pickle
>>> class CustomException(Exception):
... def __init__(self, arg1, arg2):
... msg = "Custom message {} {}".format(arg1, arg2)
... super().__init__(msg)
...
>>> obj_dump = pickle.dumps(CustomException("arg1", "arg2"))
>>> obj = pickle.loads(obj_dump)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: CustomException.__init__() missing 1 required positional argument: 'arg2'
>>>
|
|||
| msg396040 - (view) | Author: Henk-Jaap Wagenaar (cryvate) * | Date: 2021-06-18 10:15 | |
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). |
|||
| msg396601 - (view) | Author: Irit Katriel (iritkatriel) * ![]() |
Date: 2021-06-27 21:34 | |
See also issue43460, issue30005, issue29466 |
|||
| msg409867 - (view) | Author: Irit Katriel (iritkatriel) * ![]() |
Date: 2022-01-06 15:54 | |
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:
class Base:
def __init__(self, msg):
self.msg = msg
def __reduce__(self):
return type(self), (self.msg,)
class Derived(Base):
def __init__(self, a, b):
super().__init__(f'{a}|{b}')
x = Derived('a', 'b')
assert x.msg == 'a|b'
y = pickle.dumps(x, -1)
z = pickle.loads(y)
-------------------------------------------
Output:
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:
class Derived(Base):
def __init__(self, a, b):
super().__init__(f'{a}|{b}')
def __reduce__(self):
return type(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.
|
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022-04-11 14:58:57 | admin | set | github: 76877 |
| 2022-01-15 07:35:30 | zseil | set | nosy:
- zseil |
| 2022-01-14 16:49:39 | Zefir-13000 | set | nosy:
+ Zefir-13000 pull_requests: + pull_request28801 |
| 2022-01-06 16:16:09 | iritkatriel | set | status: open -> closed resolution: not a bug stage: resolved |
| 2022-01-06 16:14:03 | georg.brandl | set | nosy:
- georg.brandl |
| 2022-01-06 15:54:13 | iritkatriel | set | messages: + msg409867 |
| 2021-11-19 10:16:57 | 4-launchpad-kalvdans-no-ip-org | set | nosy:
+ 4-launchpad-kalvdans-no-ip-org |
| 2021-06-27 21:34:32 | iritkatriel | set | messages: + msg396601 |
| 2021-06-18 10:15:29 | cryvate | set | nosy:
+ cryvate messages: + msg396040 |
| 2021-06-18 08:41:12 | iritkatriel | set | nosy:
+ iritkatriel messages:
+ msg396035 |
| 2018-10-29 19:30:34 | benoit-pierre | set | nosy:
+ benoit-pierre |
| 2018-10-11 14:42:40 | orivej | set | nosy:
+ orivej |
| 2018-04-12 16:42:31 | jaraco | set | messages: + msg315230 |
| 2018-04-12 15:07:01 | Kirill Matsaberydze | set | nosy:
+ Kirill Matsaberydze messages: + msg315225 |
| 2018-01-28 16:15:55 | slallum | create | |
