Skip to content

Commit

Permalink
Show full stack trace on exception with __cause__ or __context__. Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
fabioz committed Jan 7, 2021
1 parent 59ee2ed commit a31af63
Show file tree
Hide file tree
Showing 10 changed files with 2,400 additions and 2,058 deletions.
74 changes: 48 additions & 26 deletions src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
from _pydevd_bundle.pydevd_thread_lifecycle import pydevd_find_thread_by_id, resume_threads
from _pydevd_bundle.pydevd_dont_trace_files import PYDEV_FILE
import dis
from _pydevd_bundle.pydevd_frame_utils import create_frames_list_from_exception_cause
try:
from urllib import quote_plus, unquote_plus # @UnresolvedImport
except:
Expand Down Expand Up @@ -1196,33 +1197,57 @@ def build_exception_info_response(dbg, thread_id, request_seq, set_additional_th
additional_info = set_additional_thread_info(thread)
topmost_frame = additional_info.get_topmost_frame(thread)

frames = []
exc_type = None
exc_desc = None
current_paused_frame_name = ''

source_path = '' # This is an extra bit of data used by Visual Studio
stack_str_lst = []

if topmost_frame is not None:
try:
frames_list = dbg.suspended_frames_manager.get_frames_list(thread_id)
if frames_list is not None:
exc_type = frames_list.exc_type
exc_desc = frames_list.exc_desc
trace_obj = frames_list.trace_obj
for frame_id, frame, method_name, original_filename, filename_in_utf8, lineno, _applied_mapping, show_as_current_frame in \
iter_visible_frames_info(dbg, frames_list):

line_text = linecache.getline(original_filename, lineno)

# Never filter out plugin frames!
if not getattr(frame, 'IS_PLUGIN_FRAME', False):
if dbg.is_files_filter_enabled and dbg.apply_files_filter(frame, original_filename, False):
continue
try:
frames_list = dbg.suspended_frames_manager.get_frames_list(thread_id)
memo = set()
while frames_list is not None and len(frames_list):
frames = []

exc_type = frames_list.exc_type
exc_desc = frames_list.exc_desc
trace_obj = frames_list.trace_obj
frame = None

for frame_id, frame, method_name, original_filename, filename_in_utf8, lineno, _applied_mapping, show_as_current_frame in \
iter_visible_frames_info(dbg, frames_list):

line_text = linecache.getline(original_filename, lineno)

# Never filter out plugin frames!
if not getattr(frame, 'IS_PLUGIN_FRAME', False):
if dbg.is_files_filter_enabled and dbg.apply_files_filter(frame, original_filename, False):
continue

if show_as_current_frame:
current_paused_frame_name = method_name
method_name += ' (Current frame)'
frames.append((filename_in_utf8, lineno, method_name, line_text))

if not source_path and frames:
source_path = frames[0][0]

stack_str = ''.join(traceback.format_list(frames[-max_frames:]))
stack_str += frames_list.exc_context_msg
stack_str_lst.append(stack_str)

if show_as_current_frame:
current_paused_frame_name = method_name
method_name += ' (Current frame)'
frames.append((filename_in_utf8, lineno, method_name, line_text))
frames_list = create_frames_list_from_exception_cause(trace_obj, None, exc_type, exc_desc, memo)
if frames_list is None or not frames_list:
break

except:
pydev_log.exception('Error on build_exception_info_response.')
finally:
topmost_frame = None
full_stack_str = ''.join(reversed(stack_str_lst))

name = 'exception: type unknown'
if exc_type is not None:
Expand All @@ -1247,11 +1272,6 @@ def build_exception_info_response(dbg, thread_id, request_seq, set_additional_th
if current_paused_frame_name:
name += ' (note: full exception trace is shown but execution is paused at: %s)' % (current_paused_frame_name,)

stack_str = ''.join(traceback.format_list(frames[-max_frames:]))

# This is an extra bit of data used by Visual Studio
source_path = frames[0][0] if frames else ''

if thread.stop_reason == CMD_STEP_CAUGHT_EXCEPTION:
break_mode = pydevd_schema.ExceptionBreakMode.ALWAYS
else:
Expand All @@ -1268,8 +1288,10 @@ def build_exception_info_response(dbg, thread_id, request_seq, set_additional_th
details=pydevd_schema.ExceptionDetails(
message=description,
typeName=name,
stackTrace=stack_str,
source=source_path
stackTrace=full_stack_str,
source=source_path,
# Note: ExceptionDetails actually accepts an 'innerException', but
# when passing it, VSCode is not showing the stack trace at all.
)
)
)
Expand Down
Loading

0 comments on commit a31af63

Please sign in to comment.