timeout-decorator
timeout-decorator copied to clipboard
Incorrent traceback
When an Exception occurs in decorated method, it is not possible to see the real traceback. For example:
import traceback
from timeout_decorator import timeout_decorator
@timeout_decorator.timeout(10, use_signals=False)
def func():
raise Exception('Somethind went wrong')
try:
func()
except:
print(traceback.format_exc())
prints
Traceback (most recent call last): File "/home/dk/Share/test.py", line 11, in
func() File "/home/dk/.pyenv/versions/das/lib/python3.5/site-packages/timeout_decorator/timeout_decorator.py", line 91, in new_function return timeout_wrapper(*args, **kwargs) File "/home/dk/.pyenv/versions/das/lib/python3.5/site-packages/timeout_decorator/timeout_decorator.py", line 150, in call return self.value File "/home/dk/.pyenv/versions/das/lib/python3.5/site-packages/timeout_decorator/timeout_decorator.py", line 173, in value raise load Exception: Somethind went wrong
It only happens when use_signals is set to False.
This is the code that passes exception value: https://github.com/pnpnpn/timeout-decorator/blob/master/timeout_decorator/timeout_decorator.py#L108
Try passing both value (exc_info()[1]) and traceback (exc_info()[2]) there. Print traceback info with an appropriate function traceback.print_tb.
Attempting to pass the traceback directly from the background process won't work, as tracebacks can't be serialised with the pickle module by default. If that wasn't the case, the multiprocessing module would be able to correctly preserve the __traceback__ attribute on the exception instance itself.
This SO answer covers one way to handle the situation: https://stackoverflow.com/questions/6126007/python-getting-a-traceback-from-a-multiprocessing-process
That specific solution (enabling tblib's pickling support) wouldn't be appropriate for library like timeout decorator, but the to_dict and from_dict methods would allow at least the top level traceback to be passed back to the foreground process in a way that could then be used in a raise load.with_traceback(rebuilt_tb) call: https://github.com/ionelmc/python-tblib#tblib-traceback-to-dict