-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New feature: pickle Exception, its cause, and traceback #53
Comments
Darn - I just realized that Still better than not having anything though... Proof of concept: import copyreg
import pickle
from tblib import pickling_support
def pickle_exception(ex):
return unpickle_exception, (ex.__reduce__(), ex.__cause__, ex.__traceback__)
def unpickle_exception(reduce_out, cause, tb):
func, args = reduce_out
ex = func(args)
ex.__cause__ = cause
ex.__traceback__ = tb
return ex
def get_subclasses(cls):
"""Depth-first recursive traversal of all subclasses of cls
"""
to_visit = [cls, ]
while to_visit:
this = to_visit.pop()
yield this
to_visit += list(this.__subclasses__())
def patch_exceptions():
for exception_cls in get_subclasses(BaseException):
copyreg.pickle(exception_cls, pickle_exception)
class CustomError(Exception):
pass
def test():
try:
try:
1 / 0
except Exception as e:
raise CustomError("bar") from e
except Exception as e:
buf = pickle.dumps(e)
raise pickle.loads(buf)
pickling_support.install()
patch_exceptions()
test() Output:
|
It is also possible (alternatively or in addition to the above) to have a function that is applied to an exception instance just before it's sent for pickling instead: def ensure_full_exception_pickle(ex: Exception):
while ex is not None:
copyreg.pickle(ex.__class__, pickle_exception)
ex = ex.__cause__ |
So I'm generally in favor of having support for |
Can you explain the six.reraise thing a bit more or give an example? |
It's in your README.md: >>> from six import reraise
>>> reraise(*pickle.loads(s1))
As a concept it makes sense, but how do you think the API should look like? I don't think it makes sense to have a class here. Maybe two top-level functions to_dict / from_dict that can be fed an Exception or a traceback object and spit out a dict, and the reverse? |
Why wouldn't Regarding the dict api, ignore what I asked for now. Maybe it's not needed at all. |
It would continue to work, but it would not be necessary anymore - just raise will do fine |
Even after enabling tblib, when one pickles an exception, the previous exceptions in the exception chain gets lost.
This has been discussed here: dask/distributed#3158
It would be very straightforward to add to tblib an (optional?) call to
copyreg.pickle(Exception, ...)
which overrides the pickling system of the whole Exception, recursively pickles its__cause__
and__traceback__
, and automatically reassembles them upon unpickling.The behaviour for the user would be extremely straightforward (and would not require
six.reraise
anymore):I'm happy to work on a PR myself - would you be amenable to merging it?
The text was updated successfully, but these errors were encountered: