8787from _pydevd_bundle .pydevd_thread_lifecycle import pydevd_find_thread_by_id , resume_threads
8888from _pydevd_bundle .pydevd_dont_trace_files import PYDEV_FILE
8989import dis
90+ from _pydevd_bundle .pydevd_frame_utils import create_frames_list_from_exception_cause
9091try :
9192 from urllib import quote_plus , unquote_plus # @UnresolvedImport
9293except :
@@ -1196,62 +1197,86 @@ def build_exception_info_response(dbg, thread_id, request_seq, set_additional_th
11961197 additional_info = set_additional_thread_info (thread )
11971198 topmost_frame = additional_info .get_topmost_frame (thread )
11981199
1199- frames = []
1200- exc_type = None
1201- exc_desc = None
12021200 current_paused_frame_name = ''
1203- if topmost_frame is not None :
1204- try :
1205- frames_list = dbg .suspended_frames_manager .get_frames_list (thread_id )
1206- if frames_list is not None :
1207- exc_type = frames_list .exc_type
1208- exc_desc = frames_list .exc_desc
1209- trace_obj = frames_list .trace_obj
1210- for frame_id , frame , method_name , original_filename , filename_in_utf8 , lineno , _applied_mapping , show_as_current_frame in \
1211- iter_visible_frames_info (dbg , frames_list ):
1212-
1213- line_text = linecache .getline (original_filename , lineno )
1214-
1215- # Never filter out plugin frames!
1216- if not getattr (frame , 'IS_PLUGIN_FRAME' , False ):
1217- if dbg .is_files_filter_enabled and dbg .apply_files_filter (frame , original_filename , False ):
1218- continue
12191201
1220- if show_as_current_frame :
1221- current_paused_frame_name = method_name
1222- method_name += ' (Current frame)'
1223- frames .append ((filename_in_utf8 , lineno , method_name , line_text ))
1224- finally :
1225- topmost_frame = None
1202+ source_path = '' # This is an extra bit of data used by Visual Studio
1203+ stack_str_lst = []
1204+ name = None
1205+ description = None
12261206
1227- name = 'exception: type unknown'
1228- if exc_type is not None :
1207+ if topmost_frame is not None :
12291208 try :
1230- name = exc_type .__qualname__
1231- except :
12321209 try :
1233- name = exc_type .__name__
1210+ frames_list = dbg .suspended_frames_manager .get_frames_list (thread_id )
1211+ memo = set ()
1212+ while frames_list is not None and len (frames_list ):
1213+ frames = []
1214+
1215+ frame = None
1216+
1217+ if not name :
1218+ exc_type = frames_list .exc_type
1219+ if exc_type is not None :
1220+ try :
1221+ name = exc_type .__qualname__
1222+ except :
1223+ try :
1224+ name = exc_type .__name__
1225+ except :
1226+ try :
1227+ name = str (exc_type )
1228+ except :
1229+ pass
1230+
1231+ if not description :
1232+ exc_desc = frames_list .exc_desc
1233+ if exc_desc is not None :
1234+ try :
1235+ description = str (exc_desc )
1236+ except :
1237+ pass
1238+
1239+ for frame_id , frame , method_name , original_filename , filename_in_utf8 , lineno , _applied_mapping , show_as_current_frame in \
1240+ iter_visible_frames_info (dbg , frames_list ):
1241+
1242+ line_text = linecache .getline (original_filename , lineno )
1243+
1244+ # Never filter out plugin frames!
1245+ if not getattr (frame , 'IS_PLUGIN_FRAME' , False ):
1246+ if dbg .is_files_filter_enabled and dbg .apply_files_filter (frame , original_filename , False ):
1247+ continue
1248+
1249+ if show_as_current_frame :
1250+ current_paused_frame_name = method_name
1251+ method_name += ' (Current frame)'
1252+ frames .append ((filename_in_utf8 , lineno , method_name , line_text ))
1253+
1254+ if not source_path and frames :
1255+ source_path = frames [0 ][0 ]
1256+
1257+ stack_str = '' .join (traceback .format_list (frames [- max_frames :]))
1258+ stack_str += frames_list .exc_context_msg
1259+ stack_str_lst .append (stack_str )
1260+
1261+ frames_list = create_frames_list_from_exception_cause (
1262+ frames_list .trace_obj , None , frames_list .exc_type , frames_list .exc_desc , memo )
1263+ if frames_list is None or not frames_list :
1264+ break
1265+
12341266 except :
1235- try :
1236- name = str ( exc_type )
1237- except :
1238- pass
1267+ pydev_log . exception ( 'Error on build_exception_info_response.' )
1268+ finally :
1269+ topmost_frame = None
1270+ full_stack_str = '' . join ( reversed ( stack_str_lst ))
12391271
1240- description = 'exception: no description'
1241- if exc_desc is not None :
1242- try :
1243- description = str (exc_desc )
1244- except :
1245- pass
1272+ if not name :
1273+ name = 'exception: type unknown'
1274+ if not description :
1275+ description = 'exception: no description'
12461276
12471277 if current_paused_frame_name :
12481278 name += ' (note: full exception trace is shown but execution is paused at: %s)' % (current_paused_frame_name ,)
12491279
1250- stack_str = '' .join (traceback .format_list (frames [- max_frames :]))
1251-
1252- # This is an extra bit of data used by Visual Studio
1253- source_path = frames [0 ][0 ] if frames else ''
1254-
12551280 if thread .stop_reason == CMD_STEP_CAUGHT_EXCEPTION :
12561281 break_mode = pydevd_schema .ExceptionBreakMode .ALWAYS
12571282 else :
@@ -1268,8 +1293,10 @@ def build_exception_info_response(dbg, thread_id, request_seq, set_additional_th
12681293 details = pydevd_schema .ExceptionDetails (
12691294 message = description ,
12701295 typeName = name ,
1271- stackTrace = stack_str ,
1272- source = source_path
1296+ stackTrace = full_stack_str ,
1297+ source = source_path ,
1298+ # Note: ExceptionDetails actually accepts an 'innerException', but
1299+ # when passing it, VSCode is not showing the stack trace at all.
12731300 )
12741301 )
12751302 )
0 commit comments