1010import re
1111import socket
1212import sys
13+ import traceback
1314import types
1415
1516def eprint (* args , ** kwargs ):
@@ -249,15 +250,19 @@ class TraceStep:
249250 stack : Stack
250251 heap : Heap
251252 stdout : str
253+ traceback_text : str
252254
253255 def format (self ):
254- return {
256+ step = {
255257 "line" : self .line ,
256258 "filePath" : self .file_path ,
257259 "stack" : self .stack .format (),
258260 "heap" : self .heap .format (),
259261 "stdout" : self .stdout ,
260262 }
263+ if self .traceback_text is not None :
264+ step ["traceback" ] = self .traceback_text
265+ return step
261266
262267
263268def should_ignore (variable_name , value , script_path , ignore_list = []):
@@ -373,7 +378,8 @@ def trace_dispatch(self, frame, event, arg):
373378 self .import_following = import_regex .search (next_source_line ) is not None
374379
375380 display_return = event == "return" and self .last_event != "exception" and len (self .stack .frames ) > 1
376- if event == "line" or display_return :
381+ display_exception = event == "exception" and self .last_event != "return"
382+ if event == "line" or display_return or display_exception :
377383 for variable_name in frame .f_locals :
378384 if should_ignore_on_stack (variable_name , frame .f_locals [variable_name ], self .filename , self .stack_ignore ):
379385 continue
@@ -385,7 +391,15 @@ def trace_dispatch(self, frame, event, arg):
385391 heap = generate_heap (frame , self .filename , self .stack_ignore )
386392 accumulated_stdout = self .accumulated_stdout + self .captured_stdout .getvalue ()
387393
388- step = TraceStep (line , filename , copy .deepcopy (self .stack ), copy .deepcopy (heap ), accumulated_stdout )
394+ traceback_text = None
395+ if event == "exception" :
396+ exception_value = arg [1 ]
397+ traceback_text_tmp = io .StringIO ()
398+ traceback .print_exception (exception_value , file = traceback_text_tmp )
399+ traceback_text = traceback_text_tmp .getvalue ()
400+
401+
402+ step = TraceStep (line , filename , copy .deepcopy (self .stack ), copy .deepcopy (heap ), accumulated_stdout , traceback_text )
389403
390404 is_annotation = next_source_line .startswith ("@" )
391405 should_display_step = not is_annotation
@@ -408,6 +422,10 @@ def trace_dispatch(self, frame, event, arg):
408422 self .shown_class_defs .append (filename , line )
409423 self .last_step_was_class = is_class_def
410424 self .prev_num_frames = num_frames
425+
426+ if event == "exception" :
427+ # Terminate visualization after first exception in user code
428+ self .set_quit ()
411429 if event == "call" :
412430 self .stack .push_frame (frame )
413431 self .shown_class_defs .push_frame ()
0 commit comments