-
Notifications
You must be signed in to change notification settings - Fork 7
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
pkdexc leaves out important information on python 3 #29
Comments
Just to be clear for py3 (ignoring py2 case for simplicity): e = sys.exc_info()
return ''.join(traceback.format_exception_only(e[0], e[1], e[2]) |
|
Sorry, I meant to write that. :) |
I don't think format_exception works right. The goal of pkdexc is to give the entire context of the error, including the callstack from the point of where pkdexc() is called. This is why pkdexc() is different from just calling pkdebug_test.test_pkdexc Traceback (most recent call last):
File "/home/vagrant/src/radiasoft/pykern/tests/pkdebug_test.py", line 230, in tag1234
force_error()
File "/home/vagrant/src/radiasoft/pykern/tests/pkdebug_test.py", line 226, in force_error
xyzzy
NameError: name 'xyzzy' is not defined This doesn't include the calling routine (test_pkdexc) so the test fails. Here's my proposed solution, which allows the test to pass: e = sys.exc_info()
# py2 doesn't cascade exceptions
stack = traceback.format_stack()[:-2]
if hasattr(traceback, 'TracebackException'):
stack += traceback.format_exception(*e)
else:
stack += traceback.format_tb(e[2])
return ''.join(traceback.format_exception_only(e[0], e[1]) + stack) |
format_exception gives more info than just getting the stack from the exception in py3.
Right that's what I was saying here :-)
I think your proposed solution gives confusing output if the exception has Here's some code: def raise_KeyError():
dict()['foo']
def exposed_api():
try:
raise_KeyError()
except KeyError:
# Replace the exception with something else
raise RuntimeError('got a KeyError')
def outer_func():
try:
exposed_api()
except:
print(''.join(traceback.format_exception(*sys.exc_info())))
outer_func() Here's what it prints:
Notice that it's kind of "inside out" – inside each section you read from bottom to top, but you read the sections themselves from top to bottom. The place marked
|
Fix #29 correct ordering of stacks in py3
In Python 3, exceptions carry more contextual information than just their traceback. They also have
.__context__
and.__cause__
attributes that carry information about other exceptions that may have triggered this one. And then those exceptions might have their own.__context__
and.__cause__
. (See PEP 3134 for details.)This gets even more complex with trio, because you have to handle "exception groups" (when multiple unhandled exceptions are raised simultaneously in different branches of the call tree, and then end up getting grouped together).
Unfortunately, pkdexc doesn't know about any of this stuff: it just formats the latest exception's traceback, and throws away all the contextual information:
pykern/pykern/pkdebug.py
Lines 159 to 165 in 784dded
I think the simplest thing to do on python 3 is to use
traceback.format_exception
which does know how to handle all this stuff. For example:This does mean we can't as easily graft the current stack onto the exception's stack, like
pkdexc
does now. But we could print the current stack with a little header likeException encountered at:\n
+ current stack +format_exception
output.The text was updated successfully, but these errors were encountered: