timeout: Re-raise from where the TimeoutExpired hit the thread.

Having just thrown an exception into the thread, it is often useful to
know _what_ was the slow code that we interrupted.  Raising a bare
TimeoutExpired here obscures that information, as any `exc_info` will
end there.

Examine the thread for any exception information, and use that to
re-raise.  This exception information is not guaranteed to exist -- if
the thread didn't respond to the exception in time, or caught it, for
instance.
This commit is contained in:
Alex Vandiver
2022-04-05 11:29:47 -07:00
committed by Tim Abbott
parent 85eeaf5f18
commit e714264756

View File

@@ -78,11 +78,14 @@ def timeout(timeout: float, func: Callable[[], ResultT]) -> ResultT:
time.sleep(0.1)
if not thread.is_alive():
break
if thread.exc_info[1] is not None:
# Re-raise the exception we sent, if possible, so the
# stacktrace originates in the slow code
raise thread.exc_info[1].with_traceback(thread.exc_info[2])
raise TimeoutExpired
if thread.exc_info[1] is not None:
# Raise the original stack trace so our error messages are more useful.
# from https://stackoverflow.com/a/4785766/90777
# Died with some other exception; re-raise it
raise thread.exc_info[1].with_traceback(thread.exc_info[2])
assert thread.result is not None # assured if above did not reraise
return thread.result