Exceptions and tracebacks and frames, oh my!

Hi everyone, Apologies for pinging the dev list; I'm shaving a very hairy yak, and the python-help crew, the docs, and the source are all unable to help. Context: I'm working on a library function to dump stack traces for all threads, sorta like _Py_DumpTracebackThreads but in Python and meant to be invoked from a high layer, and thus be pretty and readable and so on rather than signal-safe and robust. The hard part is combining data from thread stack frames and exceptions, since people generally want to know about these. What I'm having trouble understanding is the relationship between an exception's TB and the thread's frame. Two important differences I've noticed are that (a) the output of traceback.print_tb(sys.exc_info()[2]) and traceback.print_stack(sys.exc_info()[2].tb_frame) are markedly different -- the former gives data about where the exception was raised, while the latter about where the thread currently is, usually in an exception handler and (b) if I'm in a unittest and dump the stack for a thread starting from its current frame (using traceback.format_stack and sys._current_frames), it gives a very deep stack that includes all the unittest harness code etc., but if I dump the stack for an exception starting from its TB object, it instead is very short and focused on where the exception happened. All of which tells me that I don't understand the relationship between the exception's traceback object and the frames it points to at all. Is there somewhere that explains this particular bit of magic, or someone who's well-versed in it? I have to admit that after a few hours of spelunking the code, I can't even figure out how the exception traceback is being set in the first place. :) Again, apologies for bugging the dev list with what (I hope) is a simple question -- if there's a FM I should be reading, please let me know! Yonatan

This may be something you've already figured out, or not useful for your use case, but the key insight here tends to be that traceback objects form a singly-linked list from the frame where the exception was caught up to the frame where it was raised, whereas the frames are linked in the opposite direction, from the most deeply nested frame down to the main/root frame (or the start/bootstrap frame for threads). Tracebacks link to the frame. The lineno in the traceback is where the exception was raised (or bubbled out) whereas the lineno in the frame is where the frame is currently executing (probably in the exception handling code). On Thu, Jul 14, 2022 at 1:05 PM Yonatan Zunger <zunger@gmail.com> wrote:
Hi everyone,
Apologies for pinging the dev list; I'm shaving a very hairy yak, and the python-help crew, the docs, and the source are all unable to help.
Context: I'm working on a library function to dump stack traces for all threads, sorta like _Py_DumpTracebackThreads but in Python and meant to be invoked from a high layer, and thus be pretty and readable and so on rather than signal-safe and robust. The hard part is combining data from thread stack frames and exceptions, since people generally want to know about these.
What I'm having trouble understanding is the relationship between an exception's TB and the thread's frame. Two important differences I've noticed are that (a) the output of traceback.print_tb(sys.exc_info()[2]) and traceback.print_stack(sys.exc_info()[2].tb_frame) are markedly different -- the former gives data about where the exception was raised, while the latter about where the thread currently is, usually in an exception handler and (b) if I'm in a unittest and dump the stack for a thread starting from its current frame (using traceback.format_stack and sys._current_frames), it gives a very deep stack that includes all the unittest harness code etc., but if I dump the stack for an exception starting from its TB object, it instead is very short and focused on where the exception happened.
All of which tells me that I don't understand the relationship between the exception's traceback object and the frames it points to at all.
Is there somewhere that explains this particular bit of magic, or someone who's well-versed in it? I have to admit that after a few hours of spelunking the code, I can't even figure out how the exception traceback is being set in the first place. :)
Again, apologies for bugging the dev list with what (I hope) is a simple question -- if there's a FM I should be reading, please let me know!
Yonatan _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-leave@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/IRPWIRAZ... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
participants (2)
-
Guido van Rossum
-
Yonatan Zunger