From 76cf4f645675e252edd8530ce5244d48d5ee3e47 Mon Sep 17 00:00:00 2001 From: Tim Savannah Date: Wed, 24 May 2017 02:01:58 -0400 Subject: [PATCH] Much better exception handling - Have them make more sense. Get rid of the multiple traceback prints, one for each level of catchs on python3. Also improve traceback on both python3 and python2 to exclude the function wrapper, and instead follow the execution frame. Downside is that neither form compiles on the other python, so have to use exec... --- func_timeout/dafunc.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/func_timeout/dafunc.py b/func_timeout/dafunc.py index 4debe6a..6667785 100644 --- a/func_timeout/dafunc.py +++ b/func_timeout/dafunc.py @@ -61,9 +61,14 @@ def func_timeout(timeout, func, args=(), kwargs=None): # Don't print traceback to stderr if we time out pass except Exception as e: + exc_info = sys.exc_info() if isStopped is False: - # Don't capture stopping exception - exception.append(e) + # Assemble the alternate traceback, excluding this function + # from the trace (by going to next frame) + # Pytohn3 reads native from __traceback__, + # python2 has a different form for "raise" + e.__traceback__ = exc_info[2].tb_next + exception.append( e ) thread = StoppableThread(target=funcwrap, args=(args, kwargs)) thread.daemon = True @@ -96,9 +101,10 @@ def func_timeout(timeout, func, args=(), kwargs=None): # This, in effect, prevents the "funcwrap" wrapper ( chained # in context to an exception raised here, due to scope ) # Only available in python3.3+ - exec('raise exception[0] from None', None, { 'exception' : exception }) + exec('raise exception[0] from None', None, { 'exception' : exception, }) else: - raise exception[0] + # Python2 allows specifying an alternate traceback. + exec('raise exception[0] , None, exception[0].__traceback__', None, {'exception' : exception}) if ret: return ret[0]