Description
from PEP 554:
Regarding uncaught exceptions in Interpreter.run(), we noted that they are "effectively" propagated into the code where run() was called. To prevent leaking exceptions (and tracebacks) between interpreters, we create a surrogate of the exception and its traceback (see traceback.TracebackException), set it to cause on a new RunFailedError, and raise that.
Raising (a proxy of) the exception directly is problematic since it's harder to distinguish between an error in the run() call and an uncaught exception from the subinterpreter.
Currently uncaught exceptions from Interpreter.run()
are stringified and then wrapped in a RunFailedError
before being raised in the calling interpreter. This was fine in theory. However, as I've been using subinterpreters in tests I've found that this approach is extremely cumbersome for two reasons:
- boilerplate (much more often than expected) to deal with the original exception (see Raise the "original" exception from Interpreter.run()? #43)
- no tracebacks
The solution: "propagate" the original exception and traceback through to the calling interpreter. This is tricky because the exception and traceback must go through the cross-interpreter data machinery. The result would be an exception that matches the original (i.e. a proxy), including a traceback that works as an effective substitute (and any __cause__
, etc. set).
Once that is sorted out, we'll set the __cause__
of the raised RunFailedError
to the proxy of the original exception. We would end up with tracebacks that look like this:
>>> interp.run(script)
Traceback (most recent call last):
File "<stdin>", line 3
raise SpamError('eggs')
SpamError: eggs
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 7
interp.run(script)
RunFailedError: SpamError: eggs
>>> try:
... interp.run(script)
... except RunFailedError as exc:
... raise exc.__cause__
...
Traceback (most recent call last):
File "<stdin>", line 3
raise SpamError('eggs')
SpamError: eggs
Also, how do we get the traceback (e.g. lineno) right?