Fix pickling of httpclient.HTTPError subclasses and web.HTTPError#3439
Fix pickling of httpclient.HTTPError subclasses and web.HTTPError#3439andersk wants to merge 1 commit intotornadoweb:masterfrom
httpclient.HTTPError subclasses and web.HTTPError#3439Conversation
c9309d0 to
9cb31f2
Compare
|
|
|
One common situation where exception pickling comes up is import multiprocessing, tornado
def f():
raise tornado.simple_httpclient.HTTPTimeoutError("message")
with multiprocessing.Pool() as pool:
pool.apply(f)This not only fails to propagate the raised error, but in fact wedges the whole process while trying. |
The `args` member variable is set by `BaseException.__new__` and used
by `BaseException.__reduce__` for pickling. To avoid interfering with
it, we need to avoid calling `BaseException.__init__` from classes
that have subclasses with incompatible constructors, and rename our
own `tornado.web.HTTPError.args` member.
>>> pickle.loads(pickle.dumps(tornado.simple_httpclient.HTTPTimeoutError("message")))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: HTTPTimeoutError.__init__() takes 2 positional arguments but 4 were given
>>> str(pickle.loads(pickle.dumps(tornado.web.HTTPError(500, "%s", "foo"))))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/anders/python/tornado/tornado/web.py", line 2488, in __str__
return message + " (" + (self.log_message % self.args) + ")"
~~~~~~~~~~~~~~~~~^~~~~~~~~~~
TypeError: not enough arguments for format string
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
|
Right. It was a mistake to use |
The
argsmember variable is set byBaseException.__new__and used byBaseException.__reduce__for pickling. To avoid interfering with it, we need to avoid callingBaseException.__init__from classes that have subclasses with incompatible constructors, and rename our owntornado.web.HTTPError.argsmember.>>> pickle.loads(pickle.dumps(tornado.simple_httpclient.HTTPTimeoutError("message"))) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: HTTPTimeoutError.__init__() takes 2 positional arguments but 4 were given >>> str(pickle.loads(pickle.dumps(tornado.web.HTTPError(500, "%s", "foo")))) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/anders/python/tornado/tornado/web.py", line 2488, in __str__ return message + " (" + (self.log_message % self.args) + ")" ~~~~~~~~~~~~~~~~~^~~~~~~~~~~ TypeError: not enough arguments for format string