1010import re
1111import socket
1212import sys
13+ import traceback
1314import types
1415import typing
1516
@@ -253,15 +254,19 @@ class TraceStep:
253254 stack : Stack
254255 heap : Heap
255256 stdout : str
257+ traceback_text : str
256258
257259 def format (self ):
258- return {
260+ step = {
259261 "line" : self .line ,
260262 "filePath" : self .file_path ,
261263 "stack" : self .stack .format (),
262264 "heap" : self .heap .format (),
263265 "stdout" : self .stdout ,
264266 }
267+ if self .traceback_text is not None :
268+ step ["traceback" ] = self .traceback_text
269+ return step
265270
266271
267272def should_ignore (variable_name , value , script_path , ignore_list = []):
@@ -377,7 +382,8 @@ def trace_dispatch(self, frame, event, arg):
377382 self .import_following = import_regex .search (next_source_line ) is not None
378383
379384 display_return = event == "return" and self .last_event != "exception" and len (self .stack .frames ) > 1
380- if event == "line" or display_return :
385+ display_exception = event == "exception" and self .last_event != "return"
386+ if event == "line" or display_return or display_exception :
381387 for variable_name in frame .f_locals :
382388 if should_ignore_on_stack (variable_name , frame .f_locals [variable_name ], self .filename , self .stack_ignore ):
383389 continue
@@ -389,7 +395,15 @@ def trace_dispatch(self, frame, event, arg):
389395 heap = generate_heap (frame , self .filename , self .stack_ignore )
390396 accumulated_stdout = self .accumulated_stdout + self .captured_stdout .getvalue ()
391397
392- step = TraceStep (line , filename , copy .deepcopy (self .stack ), copy .deepcopy (heap ), accumulated_stdout )
398+ traceback_text = None
399+ if event == "exception" :
400+ exception_value = arg [1 ]
401+ traceback_text_tmp = io .StringIO ()
402+ traceback .print_exception (exception_value , limit = 0 , file = traceback_text_tmp )
403+ traceback_text = traceback_text_tmp .getvalue ()
404+
405+
406+ step = TraceStep (line , filename , copy .deepcopy (self .stack ), copy .deepcopy (heap ), accumulated_stdout , traceback_text )
393407
394408 is_annotation = next_source_line .startswith ("@" )
395409 should_display_step = not is_annotation
@@ -412,6 +426,10 @@ def trace_dispatch(self, frame, event, arg):
412426 self .shown_class_defs .append (filename , line )
413427 self .last_step_was_class = is_class_def
414428 self .prev_num_frames = num_frames
429+
430+ if event == "exception" :
431+ # Terminate visualization after first exception in user code
432+ self .set_quit ()
415433 if event == "call" :
416434 self .stack .push_frame (frame )
417435 self .shown_class_defs .push_frame ()
0 commit comments