mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-62566 Reduce code duplication; remove PyDBFrame from plugin API function arguments; regenerate binaries
GitOrigin-RevId: 4b9831d52d44142619b11200a563c149971fe4b4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6104b06e48
commit
f3cb61ff59
@@ -13,7 +13,7 @@ boolean isMac = Os.isFamily(Os.FAMILY_MAC)
|
||||
|
||||
envs {
|
||||
String python27version = "2.7.18"
|
||||
String python36version = "3.6.8" // latest available installer
|
||||
String python36version = (isWindows) ? "3.6.8" : "3.6.15" // 3.6.8 is broken on modern libc and clang, but latest version for Windows
|
||||
String python37version = "3.7.9"
|
||||
String python38version = "3.8.10"
|
||||
String python39version = "3.9.13"
|
||||
|
||||
@@ -7,7 +7,7 @@ from _pydev_bundle import pydev_log
|
||||
from _pydevd_bundle.pydevd_frame import PyDBFrame
|
||||
# ENDIF
|
||||
|
||||
version = 37
|
||||
version = 38
|
||||
|
||||
if not hasattr(sys, '_current_frames'):
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ from collections import namedtuple
|
||||
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY3K, IS_CPYTHON
|
||||
|
||||
__all__ = ["get_smart_step_into_candidates"]
|
||||
__all__ = ["find_last_call_name", "find_last_func_call_order",
|
||||
"get_smart_step_into_candidates"]
|
||||
|
||||
_LOAD_OPNAMES = {
|
||||
'LOAD_BUILD_CLASS',
|
||||
|
||||
+22720
-15066
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ pydev_log.debug("Using Cython speedups")
|
||||
# from _pydevd_bundle.pydevd_frame import PyDBFrame
|
||||
# ENDIF
|
||||
|
||||
version = 37
|
||||
version = 38
|
||||
|
||||
if not hasattr(sys, '_current_frames'):
|
||||
|
||||
@@ -193,7 +193,7 @@ from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE, PYDEV_FILE
|
||||
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, just_raised, remove_exception_from_frame, ignore_exception_trace
|
||||
from _pydevd_bundle.pydevd_bytecode_utils import find_last_call_name, find_last_func_call_order
|
||||
from _pydevd_bundle.pydevd_utils import get_clsname_for_code, should_stop_on_failed_test, is_exception_in_test_unit_can_be_ignored, eval_expression
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, is_real_file
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame
|
||||
|
||||
try:
|
||||
from inspect import CO_GENERATOR
|
||||
@@ -270,6 +270,242 @@ def handle_breakpoint_expression(breakpoint, info, new_frame):
|
||||
info.pydev_message = str(val)
|
||||
|
||||
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
def should_stop_on_exception(tuple args, frame, str event, tuple arg):
|
||||
cdef PyDBAdditionalThreadInfo info;
|
||||
cdef bint flag;
|
||||
# ELSE
|
||||
# def should_stop_on_exception(args, frame, event, arg):
|
||||
# ENDIF
|
||||
|
||||
# main_debugger, _filename, info, _thread = args
|
||||
main_debugger = args[0]
|
||||
info = args[2]
|
||||
should_stop = False
|
||||
|
||||
# STATE_SUSPEND = 2
|
||||
if info.pydev_state != 2: # and breakpoint is not None:
|
||||
exception, value, trace = arg
|
||||
|
||||
if trace is not None and hasattr(trace, 'tb_next'):
|
||||
# on jython trace is None on the first event and it may not have a tb_next.
|
||||
|
||||
exception_breakpoint = get_exception_breakpoint(
|
||||
exception, main_debugger.break_on_caught_exceptions)
|
||||
|
||||
if exception_breakpoint is not None:
|
||||
if exception_breakpoint.condition is not None:
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
eval_result = handle_breakpoint_condition(main_debugger, info, exception_breakpoint, frame)
|
||||
remove_exception_from_frame(frame)
|
||||
if not eval_result:
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.ignore_libraries:
|
||||
if not main_debugger.is_exception_trace_in_project_scope(trace):
|
||||
return False, frame
|
||||
|
||||
if ignore_exception_trace(trace):
|
||||
return False, frame
|
||||
|
||||
was_just_raised = just_raised(trace)
|
||||
if was_just_raised:
|
||||
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# Option: Don't break if an exception is caught in the same function from which it is thrown
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.notify_on_first_raise_only:
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# In this case we never stop if it was just raised, so, to know if it was the first we
|
||||
# need to check if we're in the 2nd method.
|
||||
if not was_just_raised and not just_raised(trace.tb_next):
|
||||
return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception
|
||||
|
||||
else:
|
||||
if not was_just_raised and not main_debugger.is_top_level_trace_in_project_scope(trace):
|
||||
return False, frame # I.e.: we stop only when it was just raised
|
||||
|
||||
# If it got here we should stop.
|
||||
should_stop = True
|
||||
try:
|
||||
info.pydev_message = exception_breakpoint.qname
|
||||
except:
|
||||
info.pydev_message = exception_breakpoint.qname.encode('utf-8')
|
||||
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
|
||||
info.pydev_message = "python-%s" % info.pydev_message
|
||||
|
||||
else:
|
||||
# No regular exception breakpoint, let's see if some plugin handles it or if it is a test assertion error.
|
||||
try:
|
||||
if main_debugger.plugin is not None:
|
||||
result = main_debugger.plugin.exception_break(main_debugger, frame, args, arg)
|
||||
if result:
|
||||
should_stop, frame = result
|
||||
if main_debugger.stop_on_failed_tests and main_debugger.is_test_item_or_set_up_caller(trace) \
|
||||
and not is_exception_in_test_unit_can_be_ignored(exception):
|
||||
should_stop, frame = should_stop_on_failed_test(arg), frame
|
||||
info.pydev_message = "python-AssertionError"
|
||||
except:
|
||||
should_stop = False
|
||||
|
||||
if should_stop:
|
||||
if exception_breakpoint is not None and exception_breakpoint.expression is not None:
|
||||
handle_breakpoint_expression(exception_breakpoint, info, frame)
|
||||
|
||||
return should_stop, frame
|
||||
|
||||
|
||||
# Same thing in the main debugger but only considering the file contents,
|
||||
# while the one in the main debugger considers the user input (so, the actual result
|
||||
# must be a join of both).
|
||||
filename_to_lines_where_exceptions_are_ignored = {}
|
||||
filename_to_stat_info = {}
|
||||
|
||||
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
def handle_exception(tuple args, frame, str event, tuple arg):
|
||||
# ELSE
|
||||
# def handle_exception(args, frame, event, arg):
|
||||
# ENDIF
|
||||
try:
|
||||
# We have 3 things in arg: exception type, description, traceback object
|
||||
trace_obj = arg[2]
|
||||
main_debugger = args[0]
|
||||
|
||||
initial_trace_obj = trace_obj
|
||||
if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
|
||||
# I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
|
||||
pass
|
||||
else:
|
||||
# Get the trace_obj from where the exception was raised...
|
||||
while trace_obj.tb_next is not None:
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
if main_debugger.ignore_exceptions_thrown_in_lines_with_ignore_exception \
|
||||
and not main_debugger.stop_on_failed_tests:
|
||||
for check_trace_obj in (initial_trace_obj, trace_obj):
|
||||
filename = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)[1]
|
||||
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if lines_ignored is None:
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}
|
||||
|
||||
try:
|
||||
curr_stat = os.stat(filename)
|
||||
curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
|
||||
except:
|
||||
curr_stat = None
|
||||
|
||||
last_stat = filename_to_stat_info.get(filename)
|
||||
if last_stat != curr_stat:
|
||||
filename_to_stat_info[filename] = curr_stat
|
||||
lines_ignored.clear()
|
||||
try:
|
||||
linecache.checkcache(filename)
|
||||
except:
|
||||
# Jython 2.1
|
||||
linecache.checkcache()
|
||||
|
||||
from_user_input = main_debugger.filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if from_user_input:
|
||||
merged = {}
|
||||
merged.update(lines_ignored)
|
||||
# Override what we have with the related entries that the user entered
|
||||
merged.update(from_user_input)
|
||||
else:
|
||||
merged = lines_ignored
|
||||
|
||||
exc_lineno = check_trace_obj.tb_lineno
|
||||
|
||||
# print ('lines ignored', lines_ignored)
|
||||
# print ('user input', from_user_input)
|
||||
# print ('merged', merged, 'curr', exc_lineno)
|
||||
|
||||
if exc_lineno not in merged: # Note: check on merged but update lines_ignored.
|
||||
try:
|
||||
line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
|
||||
except:
|
||||
# Jython 2.1
|
||||
line = linecache.getline(filename, exc_lineno)
|
||||
|
||||
if IGNORE_EXCEPTION_TAG.match(line) is not None:
|
||||
lines_ignored[exc_lineno] = 1
|
||||
return
|
||||
else:
|
||||
# Put in the cache saying not to ignore
|
||||
lines_ignored[exc_lineno] = 0
|
||||
else:
|
||||
# Ok, dict has it already cached, so, let's check it...
|
||||
if merged.get(exc_lineno, 0):
|
||||
return
|
||||
|
||||
thread = args[3]
|
||||
|
||||
try:
|
||||
frame_id_to_frame = {}
|
||||
frame_id_to_frame[id(frame)] = frame
|
||||
f = trace_obj.tb_frame
|
||||
while f is not None:
|
||||
frame_id_to_frame[id(f)] = f
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
thread_id = get_current_thread_id(thread)
|
||||
|
||||
if main_debugger.stop_on_failed_tests:
|
||||
# Our goal is to find the deepest frame in stack that still belongs to the project and stop there.
|
||||
f = trace_obj.tb_frame
|
||||
while f:
|
||||
abs_path, _, _ = get_abs_path_real_path_and_base_from_frame(f)
|
||||
if main_debugger.in_project_scope(abs_path):
|
||||
frame = f
|
||||
break
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
trace_obj = initial_trace_obj
|
||||
while trace_obj:
|
||||
if trace_obj.tb_frame is frame:
|
||||
break
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
add_exception_to_frame(frame, (arg[0], arg[1], trace_obj))
|
||||
|
||||
pydevd_vars.add_additional_frame_by_id(thread_id, frame_id_to_frame)
|
||||
|
||||
try:
|
||||
main_debugger.send_caught_exception_stack(thread, arg, id(frame))
|
||||
main_debugger.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
|
||||
main_debugger.do_wait_suspend(thread, frame, event, arg)
|
||||
main_debugger.send_caught_exception_stack_proceeded(thread)
|
||||
|
||||
finally:
|
||||
pydevd_vars.remove_additional_frame_by_id(thread_id)
|
||||
except KeyboardInterrupt as e:
|
||||
raise e
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
main_debugger.set_trace_for_frame_and_parents(frame)
|
||||
finally:
|
||||
# Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
|
||||
remove_exception_from_frame(frame)
|
||||
# Clear some local variables...
|
||||
frame = None
|
||||
trace_obj = None
|
||||
initial_trace_obj = None
|
||||
check_trace_obj = None
|
||||
f = None
|
||||
frame_id_to_frame = None
|
||||
main_debugger = None
|
||||
thread = None
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
# PyDBFrame
|
||||
#=======================================================================================================================
|
||||
@@ -285,11 +521,6 @@ cdef class PyDBFrame:
|
||||
|
||||
# Note: class (and not instance) attributes.
|
||||
|
||||
# Same thing in the main debugger but only considering the file contents, while the one in the main debugger
|
||||
# considers the user input (so, the actual result must be a join of both).
|
||||
filename_to_lines_where_exceptions_are_ignored = {}
|
||||
filename_to_stat_info = {}
|
||||
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
cdef tuple _args
|
||||
cdef int should_skip
|
||||
@@ -323,10 +554,10 @@ cdef class PyDBFrame:
|
||||
# def trace_exception(self, frame, event, arg):
|
||||
# ENDIF
|
||||
if event == 'exception':
|
||||
should_stop, frame = self.should_stop_on_exception(frame, event, arg)
|
||||
should_stop, frame = should_stop_on_exception(self._args, frame, event, arg)
|
||||
|
||||
if should_stop:
|
||||
self.handle_exception(frame, event, arg)
|
||||
handle_exception(self._args, frame, event, arg)
|
||||
return self.trace_dispatch
|
||||
|
||||
return self.trace_exception
|
||||
@@ -337,231 +568,6 @@ cdef class PyDBFrame:
|
||||
send_signature_return_trace(main_debugger, frame, filename, arg)
|
||||
return self.trace_return
|
||||
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
def should_stop_on_exception(self, frame, str event, arg):
|
||||
cdef PyDBAdditionalThreadInfo info;
|
||||
cdef bint flag;
|
||||
# ELSE
|
||||
# def should_stop_on_exception(self, frame, event, arg):
|
||||
# ENDIF
|
||||
|
||||
# main_debugger, _filename, info, _thread = self._args
|
||||
main_debugger = self._args[0]
|
||||
info = self._args[2]
|
||||
should_stop = False
|
||||
|
||||
# STATE_SUSPEND = 2
|
||||
if info.pydev_state != 2: # and breakpoint is not None:
|
||||
exception, value, trace = arg
|
||||
|
||||
if trace is not None and hasattr(trace, 'tb_next'):
|
||||
# on jython trace is None on the first event and it may not have a tb_next.
|
||||
|
||||
exception_breakpoint = get_exception_breakpoint(
|
||||
exception, main_debugger.break_on_caught_exceptions)
|
||||
|
||||
if exception_breakpoint is not None:
|
||||
if exception_breakpoint.condition is not None:
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
eval_result = handle_breakpoint_condition(main_debugger, info, exception_breakpoint, frame)
|
||||
remove_exception_from_frame(frame)
|
||||
if not eval_result:
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.ignore_libraries:
|
||||
if not main_debugger.is_exception_trace_in_project_scope(trace):
|
||||
return False, frame
|
||||
|
||||
if ignore_exception_trace(trace):
|
||||
return False, frame
|
||||
|
||||
was_just_raised = just_raised(trace)
|
||||
if was_just_raised:
|
||||
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# Option: Don't break if an exception is caught in the same function from which it is thrown
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.notify_on_first_raise_only:
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# In this case we never stop if it was just raised, so, to know if it was the first we
|
||||
# need to check if we're in the 2nd method.
|
||||
if not was_just_raised and not just_raised(trace.tb_next):
|
||||
return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception
|
||||
|
||||
else:
|
||||
if not was_just_raised and not main_debugger.is_top_level_trace_in_project_scope(trace):
|
||||
return False, frame # I.e.: we stop only when it was just raised
|
||||
|
||||
# If it got here we should stop.
|
||||
should_stop = True
|
||||
try:
|
||||
info.pydev_message = exception_breakpoint.qname
|
||||
except:
|
||||
info.pydev_message = exception_breakpoint.qname.encode('utf-8')
|
||||
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
|
||||
info.pydev_message = "python-%s" % info.pydev_message
|
||||
|
||||
else:
|
||||
# No regular exception breakpoint, let's see if some plugin handles it or if it is a test assertion error.
|
||||
try:
|
||||
if main_debugger.plugin is not None:
|
||||
result = main_debugger.plugin.exception_break(main_debugger, self, frame, self._args, arg)
|
||||
if result:
|
||||
should_stop, frame = result
|
||||
if main_debugger.stop_on_failed_tests and main_debugger.is_test_item_or_set_up_caller(trace) \
|
||||
and not is_exception_in_test_unit_can_be_ignored(exception):
|
||||
should_stop, frame = should_stop_on_failed_test(arg), frame
|
||||
info.pydev_message = "python-AssertionError"
|
||||
except:
|
||||
should_stop = False
|
||||
|
||||
if should_stop:
|
||||
if exception_breakpoint is not None and exception_breakpoint.expression is not None:
|
||||
handle_breakpoint_expression(exception_breakpoint, info, frame)
|
||||
|
||||
return should_stop, frame
|
||||
|
||||
def handle_exception(self, frame, event, arg):
|
||||
try:
|
||||
# We have 3 things in arg: exception type, description, traceback object
|
||||
trace_obj = arg[2]
|
||||
main_debugger = self._args[0]
|
||||
|
||||
initial_trace_obj = trace_obj
|
||||
if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
|
||||
# I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
|
||||
pass
|
||||
else:
|
||||
# Get the trace_obj from where the exception was raised...
|
||||
while trace_obj.tb_next is not None:
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
if main_debugger.ignore_exceptions_thrown_in_lines_with_ignore_exception \
|
||||
and not main_debugger.stop_on_failed_tests:
|
||||
for check_trace_obj in (initial_trace_obj, trace_obj):
|
||||
filename = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)[1]
|
||||
|
||||
filename_to_lines_where_exceptions_are_ignored = self.filename_to_lines_where_exceptions_are_ignored
|
||||
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if lines_ignored is None:
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}
|
||||
|
||||
try:
|
||||
curr_stat = os.stat(filename)
|
||||
curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
|
||||
except:
|
||||
curr_stat = None
|
||||
|
||||
last_stat = self.filename_to_stat_info.get(filename)
|
||||
if last_stat != curr_stat:
|
||||
self.filename_to_stat_info[filename] = curr_stat
|
||||
lines_ignored.clear()
|
||||
try:
|
||||
linecache.checkcache(filename)
|
||||
except:
|
||||
# Jython 2.1
|
||||
linecache.checkcache()
|
||||
|
||||
from_user_input = main_debugger.filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if from_user_input:
|
||||
merged = {}
|
||||
merged.update(lines_ignored)
|
||||
# Override what we have with the related entries that the user entered
|
||||
merged.update(from_user_input)
|
||||
else:
|
||||
merged = lines_ignored
|
||||
|
||||
exc_lineno = check_trace_obj.tb_lineno
|
||||
|
||||
# print ('lines ignored', lines_ignored)
|
||||
# print ('user input', from_user_input)
|
||||
# print ('merged', merged, 'curr', exc_lineno)
|
||||
|
||||
if exc_lineno not in merged: # Note: check on merged but update lines_ignored.
|
||||
try:
|
||||
line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
|
||||
except:
|
||||
# Jython 2.1
|
||||
line = linecache.getline(filename, exc_lineno)
|
||||
|
||||
if IGNORE_EXCEPTION_TAG.match(line) is not None:
|
||||
lines_ignored[exc_lineno] = 1
|
||||
return
|
||||
else:
|
||||
# Put in the cache saying not to ignore
|
||||
lines_ignored[exc_lineno] = 0
|
||||
else:
|
||||
# Ok, dict has it already cached, so, let's check it...
|
||||
if merged.get(exc_lineno, 0):
|
||||
return
|
||||
|
||||
thread = self._args[3]
|
||||
|
||||
try:
|
||||
frame_id_to_frame = {}
|
||||
frame_id_to_frame[id(frame)] = frame
|
||||
f = trace_obj.tb_frame
|
||||
while f is not None:
|
||||
frame_id_to_frame[id(f)] = f
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
thread_id = get_current_thread_id(thread)
|
||||
|
||||
if main_debugger.stop_on_failed_tests:
|
||||
# Our goal is to find the deepest frame in stack that still belongs to the project and stop there.
|
||||
f = trace_obj.tb_frame
|
||||
while f:
|
||||
abs_path, _, _ = get_abs_path_real_path_and_base_from_frame(f)
|
||||
if main_debugger.in_project_scope(abs_path):
|
||||
frame = f
|
||||
break
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
trace_obj = initial_trace_obj
|
||||
while trace_obj:
|
||||
if trace_obj.tb_frame is frame:
|
||||
break
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
add_exception_to_frame(frame, (arg[0], arg[1], trace_obj))
|
||||
|
||||
pydevd_vars.add_additional_frame_by_id(thread_id, frame_id_to_frame)
|
||||
|
||||
try:
|
||||
main_debugger.send_caught_exception_stack(thread, arg, id(frame))
|
||||
self.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
|
||||
self.do_wait_suspend(thread, frame, event, arg)
|
||||
main_debugger.send_caught_exception_stack_proceeded(thread)
|
||||
|
||||
finally:
|
||||
pydevd_vars.remove_additional_frame_by_id(thread_id)
|
||||
except KeyboardInterrupt as e:
|
||||
raise e
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
main_debugger.set_trace_for_frame_and_parents(frame)
|
||||
finally:
|
||||
# Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
|
||||
remove_exception_from_frame(frame)
|
||||
# Clear some local variables...
|
||||
frame = None
|
||||
trace_obj = None
|
||||
initial_trace_obj = None
|
||||
check_trace_obj = None
|
||||
f = None
|
||||
frame_id_to_frame = None
|
||||
main_debugger = None
|
||||
thread = None
|
||||
|
||||
def get_func_name(self, frame):
|
||||
code_obj = frame.f_code
|
||||
func_name = code_obj.co_name
|
||||
@@ -683,9 +689,10 @@ cdef class PyDBFrame:
|
||||
|
||||
if is_exception_event:
|
||||
if has_exception_breakpoints:
|
||||
should_stop, frame = self.should_stop_on_exception(frame, event, arg)
|
||||
should_stop, frame = should_stop_on_exception(
|
||||
self._args, frame, event, arg)
|
||||
if should_stop:
|
||||
self.handle_exception(frame, event, arg)
|
||||
handle_exception(self._args, frame, event, arg)
|
||||
# No need to reset frame.f_trace to keep the same trace function.
|
||||
return self.trace_dispatch
|
||||
is_line = False
|
||||
@@ -753,7 +760,7 @@ cdef class PyDBFrame:
|
||||
|
||||
if can_skip:
|
||||
if plugin_manager is not None and main_debugger.has_plugin_line_breaks:
|
||||
can_skip = not plugin_manager.can_not_skip(main_debugger, self, frame, info)
|
||||
can_skip = not plugin_manager.can_not_skip(main_debugger, frame, info)
|
||||
|
||||
# CMD_STEP_OVER = 108
|
||||
if can_skip and main_debugger.show_return_values and info.pydev_step_cmd == 108 and frame.f_back is info.pydev_step_stop:
|
||||
@@ -852,7 +859,7 @@ cdef class PyDBFrame:
|
||||
elif step_cmd == CMD_SMART_STEP_INTO and (frame.f_back is smart_stop_frame and is_within_context):
|
||||
stop = False
|
||||
elif plugin_manager is not None and main_debugger.has_plugin_line_breaks:
|
||||
result = plugin_manager.get_breakpoint(main_debugger, self, frame, event, self._args)
|
||||
result = plugin_manager.get_breakpoint(main_debugger, frame, event, self._args)
|
||||
if result:
|
||||
exist_result = True
|
||||
flag, breakpoint, new_frame, bp_type = result
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -20,7 +20,7 @@ from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE, PYDEV_FILE
|
||||
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, just_raised, remove_exception_from_frame, ignore_exception_trace
|
||||
from _pydevd_bundle.pydevd_bytecode_utils import find_last_call_name, find_last_func_call_order
|
||||
from _pydevd_bundle.pydevd_utils import get_clsname_for_code, should_stop_on_failed_test, is_exception_in_test_unit_can_be_ignored, eval_expression
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, is_real_file
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame
|
||||
|
||||
try:
|
||||
from inspect import CO_GENERATOR
|
||||
@@ -97,6 +97,242 @@ def handle_breakpoint_expression(breakpoint, info, new_frame):
|
||||
info.pydev_message = str(val)
|
||||
|
||||
|
||||
# IFDEF CYTHON
|
||||
# def should_stop_on_exception(tuple args, frame, str event, tuple arg):
|
||||
# cdef PyDBAdditionalThreadInfo info;
|
||||
# cdef bint flag;
|
||||
# ELSE
|
||||
def should_stop_on_exception(args, frame, event, arg):
|
||||
# ENDIF
|
||||
|
||||
# main_debugger, _filename, info, _thread = args
|
||||
main_debugger = args[0]
|
||||
info = args[2]
|
||||
should_stop = False
|
||||
|
||||
# STATE_SUSPEND = 2
|
||||
if info.pydev_state != 2: # and breakpoint is not None:
|
||||
exception, value, trace = arg
|
||||
|
||||
if trace is not None and hasattr(trace, 'tb_next'):
|
||||
# on jython trace is None on the first event and it may not have a tb_next.
|
||||
|
||||
exception_breakpoint = get_exception_breakpoint(
|
||||
exception, main_debugger.break_on_caught_exceptions)
|
||||
|
||||
if exception_breakpoint is not None:
|
||||
if exception_breakpoint.condition is not None:
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
eval_result = handle_breakpoint_condition(main_debugger, info, exception_breakpoint, frame)
|
||||
remove_exception_from_frame(frame)
|
||||
if not eval_result:
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.ignore_libraries:
|
||||
if not main_debugger.is_exception_trace_in_project_scope(trace):
|
||||
return False, frame
|
||||
|
||||
if ignore_exception_trace(trace):
|
||||
return False, frame
|
||||
|
||||
was_just_raised = just_raised(trace)
|
||||
if was_just_raised:
|
||||
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# Option: Don't break if an exception is caught in the same function from which it is thrown
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.notify_on_first_raise_only:
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# In this case we never stop if it was just raised, so, to know if it was the first we
|
||||
# need to check if we're in the 2nd method.
|
||||
if not was_just_raised and not just_raised(trace.tb_next):
|
||||
return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception
|
||||
|
||||
else:
|
||||
if not was_just_raised and not main_debugger.is_top_level_trace_in_project_scope(trace):
|
||||
return False, frame # I.e.: we stop only when it was just raised
|
||||
|
||||
# If it got here we should stop.
|
||||
should_stop = True
|
||||
try:
|
||||
info.pydev_message = exception_breakpoint.qname
|
||||
except:
|
||||
info.pydev_message = exception_breakpoint.qname.encode('utf-8')
|
||||
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
|
||||
info.pydev_message = "python-%s" % info.pydev_message
|
||||
|
||||
else:
|
||||
# No regular exception breakpoint, let's see if some plugin handles it or if it is a test assertion error.
|
||||
try:
|
||||
if main_debugger.plugin is not None:
|
||||
result = main_debugger.plugin.exception_break(main_debugger, frame, args, arg)
|
||||
if result:
|
||||
should_stop, frame = result
|
||||
if main_debugger.stop_on_failed_tests and main_debugger.is_test_item_or_set_up_caller(trace) \
|
||||
and not is_exception_in_test_unit_can_be_ignored(exception):
|
||||
should_stop, frame = should_stop_on_failed_test(arg), frame
|
||||
info.pydev_message = "python-AssertionError"
|
||||
except:
|
||||
should_stop = False
|
||||
|
||||
if should_stop:
|
||||
if exception_breakpoint is not None and exception_breakpoint.expression is not None:
|
||||
handle_breakpoint_expression(exception_breakpoint, info, frame)
|
||||
|
||||
return should_stop, frame
|
||||
|
||||
|
||||
# Same thing in the main debugger but only considering the file contents,
|
||||
# while the one in the main debugger considers the user input (so, the actual result
|
||||
# must be a join of both).
|
||||
filename_to_lines_where_exceptions_are_ignored = {}
|
||||
filename_to_stat_info = {}
|
||||
|
||||
|
||||
# IFDEF CYTHON
|
||||
# def handle_exception(tuple args, frame, str event, tuple arg):
|
||||
# ELSE
|
||||
def handle_exception(args, frame, event, arg):
|
||||
# ENDIF
|
||||
try:
|
||||
# We have 3 things in arg: exception type, description, traceback object
|
||||
trace_obj = arg[2]
|
||||
main_debugger = args[0]
|
||||
|
||||
initial_trace_obj = trace_obj
|
||||
if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
|
||||
# I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
|
||||
pass
|
||||
else:
|
||||
# Get the trace_obj from where the exception was raised...
|
||||
while trace_obj.tb_next is not None:
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
if main_debugger.ignore_exceptions_thrown_in_lines_with_ignore_exception \
|
||||
and not main_debugger.stop_on_failed_tests:
|
||||
for check_trace_obj in (initial_trace_obj, trace_obj):
|
||||
filename = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)[1]
|
||||
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if lines_ignored is None:
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}
|
||||
|
||||
try:
|
||||
curr_stat = os.stat(filename)
|
||||
curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
|
||||
except:
|
||||
curr_stat = None
|
||||
|
||||
last_stat = filename_to_stat_info.get(filename)
|
||||
if last_stat != curr_stat:
|
||||
filename_to_stat_info[filename] = curr_stat
|
||||
lines_ignored.clear()
|
||||
try:
|
||||
linecache.checkcache(filename)
|
||||
except:
|
||||
# Jython 2.1
|
||||
linecache.checkcache()
|
||||
|
||||
from_user_input = main_debugger.filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if from_user_input:
|
||||
merged = {}
|
||||
merged.update(lines_ignored)
|
||||
# Override what we have with the related entries that the user entered
|
||||
merged.update(from_user_input)
|
||||
else:
|
||||
merged = lines_ignored
|
||||
|
||||
exc_lineno = check_trace_obj.tb_lineno
|
||||
|
||||
# print ('lines ignored', lines_ignored)
|
||||
# print ('user input', from_user_input)
|
||||
# print ('merged', merged, 'curr', exc_lineno)
|
||||
|
||||
if exc_lineno not in merged: # Note: check on merged but update lines_ignored.
|
||||
try:
|
||||
line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
|
||||
except:
|
||||
# Jython 2.1
|
||||
line = linecache.getline(filename, exc_lineno)
|
||||
|
||||
if IGNORE_EXCEPTION_TAG.match(line) is not None:
|
||||
lines_ignored[exc_lineno] = 1
|
||||
return
|
||||
else:
|
||||
# Put in the cache saying not to ignore
|
||||
lines_ignored[exc_lineno] = 0
|
||||
else:
|
||||
# Ok, dict has it already cached, so, let's check it...
|
||||
if merged.get(exc_lineno, 0):
|
||||
return
|
||||
|
||||
thread = args[3]
|
||||
|
||||
try:
|
||||
frame_id_to_frame = {}
|
||||
frame_id_to_frame[id(frame)] = frame
|
||||
f = trace_obj.tb_frame
|
||||
while f is not None:
|
||||
frame_id_to_frame[id(f)] = f
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
thread_id = get_current_thread_id(thread)
|
||||
|
||||
if main_debugger.stop_on_failed_tests:
|
||||
# Our goal is to find the deepest frame in stack that still belongs to the project and stop there.
|
||||
f = trace_obj.tb_frame
|
||||
while f:
|
||||
abs_path, _, _ = get_abs_path_real_path_and_base_from_frame(f)
|
||||
if main_debugger.in_project_scope(abs_path):
|
||||
frame = f
|
||||
break
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
trace_obj = initial_trace_obj
|
||||
while trace_obj:
|
||||
if trace_obj.tb_frame is frame:
|
||||
break
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
add_exception_to_frame(frame, (arg[0], arg[1], trace_obj))
|
||||
|
||||
pydevd_vars.add_additional_frame_by_id(thread_id, frame_id_to_frame)
|
||||
|
||||
try:
|
||||
main_debugger.send_caught_exception_stack(thread, arg, id(frame))
|
||||
main_debugger.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
|
||||
main_debugger.do_wait_suspend(thread, frame, event, arg)
|
||||
main_debugger.send_caught_exception_stack_proceeded(thread)
|
||||
|
||||
finally:
|
||||
pydevd_vars.remove_additional_frame_by_id(thread_id)
|
||||
except KeyboardInterrupt as e:
|
||||
raise e
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
main_debugger.set_trace_for_frame_and_parents(frame)
|
||||
finally:
|
||||
# Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
|
||||
remove_exception_from_frame(frame)
|
||||
# Clear some local variables...
|
||||
frame = None
|
||||
trace_obj = None
|
||||
initial_trace_obj = None
|
||||
check_trace_obj = None
|
||||
f = None
|
||||
frame_id_to_frame = None
|
||||
main_debugger = None
|
||||
thread = None
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
# PyDBFrame
|
||||
#=======================================================================================================================
|
||||
@@ -112,11 +348,6 @@ class PyDBFrame:
|
||||
|
||||
# Note: class (and not instance) attributes.
|
||||
|
||||
# Same thing in the main debugger but only considering the file contents, while the one in the main debugger
|
||||
# considers the user input (so, the actual result must be a join of both).
|
||||
filename_to_lines_where_exceptions_are_ignored = {}
|
||||
filename_to_stat_info = {}
|
||||
|
||||
# IFDEF CYTHON
|
||||
# cdef tuple _args
|
||||
# cdef int should_skip
|
||||
@@ -150,10 +381,10 @@ class PyDBFrame:
|
||||
def trace_exception(self, frame, event, arg):
|
||||
# ENDIF
|
||||
if event == 'exception':
|
||||
should_stop, frame = self.should_stop_on_exception(frame, event, arg)
|
||||
should_stop, frame = should_stop_on_exception(self._args, frame, event, arg)
|
||||
|
||||
if should_stop:
|
||||
self.handle_exception(frame, event, arg)
|
||||
handle_exception(self._args, frame, event, arg)
|
||||
return self.trace_dispatch
|
||||
|
||||
return self.trace_exception
|
||||
@@ -164,231 +395,6 @@ class PyDBFrame:
|
||||
send_signature_return_trace(main_debugger, frame, filename, arg)
|
||||
return self.trace_return
|
||||
|
||||
# IFDEF CYTHON
|
||||
# def should_stop_on_exception(self, frame, str event, arg):
|
||||
# cdef PyDBAdditionalThreadInfo info;
|
||||
# cdef bint flag;
|
||||
# ELSE
|
||||
def should_stop_on_exception(self, frame, event, arg):
|
||||
# ENDIF
|
||||
|
||||
# main_debugger, _filename, info, _thread = self._args
|
||||
main_debugger = self._args[0]
|
||||
info = self._args[2]
|
||||
should_stop = False
|
||||
|
||||
# STATE_SUSPEND = 2
|
||||
if info.pydev_state != 2: # and breakpoint is not None:
|
||||
exception, value, trace = arg
|
||||
|
||||
if trace is not None and hasattr(trace, 'tb_next'):
|
||||
# on jython trace is None on the first event and it may not have a tb_next.
|
||||
|
||||
exception_breakpoint = get_exception_breakpoint(
|
||||
exception, main_debugger.break_on_caught_exceptions)
|
||||
|
||||
if exception_breakpoint is not None:
|
||||
if exception_breakpoint.condition is not None:
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
eval_result = handle_breakpoint_condition(main_debugger, info, exception_breakpoint, frame)
|
||||
remove_exception_from_frame(frame)
|
||||
if not eval_result:
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.ignore_libraries:
|
||||
if not main_debugger.is_exception_trace_in_project_scope(trace):
|
||||
return False, frame
|
||||
|
||||
if ignore_exception_trace(trace):
|
||||
return False, frame
|
||||
|
||||
was_just_raised = just_raised(trace)
|
||||
if was_just_raised:
|
||||
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# Option: Don't break if an exception is caught in the same function from which it is thrown
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.notify_on_first_raise_only:
|
||||
if main_debugger.skip_on_exceptions_thrown_in_same_context:
|
||||
# In this case we never stop if it was just raised, so, to know if it was the first we
|
||||
# need to check if we're in the 2nd method.
|
||||
if not was_just_raised and not just_raised(trace.tb_next):
|
||||
return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception
|
||||
|
||||
else:
|
||||
if not was_just_raised and not main_debugger.is_top_level_trace_in_project_scope(trace):
|
||||
return False, frame # I.e.: we stop only when it was just raised
|
||||
|
||||
# If it got here we should stop.
|
||||
should_stop = True
|
||||
try:
|
||||
info.pydev_message = exception_breakpoint.qname
|
||||
except:
|
||||
info.pydev_message = exception_breakpoint.qname.encode('utf-8')
|
||||
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
|
||||
info.pydev_message = "python-%s" % info.pydev_message
|
||||
|
||||
else:
|
||||
# No regular exception breakpoint, let's see if some plugin handles it or if it is a test assertion error.
|
||||
try:
|
||||
if main_debugger.plugin is not None:
|
||||
result = main_debugger.plugin.exception_break(main_debugger, self, frame, self._args, arg)
|
||||
if result:
|
||||
should_stop, frame = result
|
||||
if main_debugger.stop_on_failed_tests and main_debugger.is_test_item_or_set_up_caller(trace) \
|
||||
and not is_exception_in_test_unit_can_be_ignored(exception):
|
||||
should_stop, frame = should_stop_on_failed_test(arg), frame
|
||||
info.pydev_message = "python-AssertionError"
|
||||
except:
|
||||
should_stop = False
|
||||
|
||||
if should_stop:
|
||||
if exception_breakpoint is not None and exception_breakpoint.expression is not None:
|
||||
handle_breakpoint_expression(exception_breakpoint, info, frame)
|
||||
|
||||
return should_stop, frame
|
||||
|
||||
def handle_exception(self, frame, event, arg):
|
||||
try:
|
||||
# We have 3 things in arg: exception type, description, traceback object
|
||||
trace_obj = arg[2]
|
||||
main_debugger = self._args[0]
|
||||
|
||||
initial_trace_obj = trace_obj
|
||||
if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
|
||||
# I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
|
||||
pass
|
||||
else:
|
||||
# Get the trace_obj from where the exception was raised...
|
||||
while trace_obj.tb_next is not None:
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
if main_debugger.ignore_exceptions_thrown_in_lines_with_ignore_exception \
|
||||
and not main_debugger.stop_on_failed_tests:
|
||||
for check_trace_obj in (initial_trace_obj, trace_obj):
|
||||
filename = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)[1]
|
||||
|
||||
filename_to_lines_where_exceptions_are_ignored = self.filename_to_lines_where_exceptions_are_ignored
|
||||
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if lines_ignored is None:
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}
|
||||
|
||||
try:
|
||||
curr_stat = os.stat(filename)
|
||||
curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
|
||||
except:
|
||||
curr_stat = None
|
||||
|
||||
last_stat = self.filename_to_stat_info.get(filename)
|
||||
if last_stat != curr_stat:
|
||||
self.filename_to_stat_info[filename] = curr_stat
|
||||
lines_ignored.clear()
|
||||
try:
|
||||
linecache.checkcache(filename)
|
||||
except:
|
||||
# Jython 2.1
|
||||
linecache.checkcache()
|
||||
|
||||
from_user_input = main_debugger.filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if from_user_input:
|
||||
merged = {}
|
||||
merged.update(lines_ignored)
|
||||
# Override what we have with the related entries that the user entered
|
||||
merged.update(from_user_input)
|
||||
else:
|
||||
merged = lines_ignored
|
||||
|
||||
exc_lineno = check_trace_obj.tb_lineno
|
||||
|
||||
# print ('lines ignored', lines_ignored)
|
||||
# print ('user input', from_user_input)
|
||||
# print ('merged', merged, 'curr', exc_lineno)
|
||||
|
||||
if exc_lineno not in merged: # Note: check on merged but update lines_ignored.
|
||||
try:
|
||||
line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
|
||||
except:
|
||||
# Jython 2.1
|
||||
line = linecache.getline(filename, exc_lineno)
|
||||
|
||||
if IGNORE_EXCEPTION_TAG.match(line) is not None:
|
||||
lines_ignored[exc_lineno] = 1
|
||||
return
|
||||
else:
|
||||
# Put in the cache saying not to ignore
|
||||
lines_ignored[exc_lineno] = 0
|
||||
else:
|
||||
# Ok, dict has it already cached, so, let's check it...
|
||||
if merged.get(exc_lineno, 0):
|
||||
return
|
||||
|
||||
thread = self._args[3]
|
||||
|
||||
try:
|
||||
frame_id_to_frame = {}
|
||||
frame_id_to_frame[id(frame)] = frame
|
||||
f = trace_obj.tb_frame
|
||||
while f is not None:
|
||||
frame_id_to_frame[id(f)] = f
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
thread_id = get_current_thread_id(thread)
|
||||
|
||||
if main_debugger.stop_on_failed_tests:
|
||||
# Our goal is to find the deepest frame in stack that still belongs to the project and stop there.
|
||||
f = trace_obj.tb_frame
|
||||
while f:
|
||||
abs_path, _, _ = get_abs_path_real_path_and_base_from_frame(f)
|
||||
if main_debugger.in_project_scope(abs_path):
|
||||
frame = f
|
||||
break
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
trace_obj = initial_trace_obj
|
||||
while trace_obj:
|
||||
if trace_obj.tb_frame is frame:
|
||||
break
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
add_exception_to_frame(frame, (arg[0], arg[1], trace_obj))
|
||||
|
||||
pydevd_vars.add_additional_frame_by_id(thread_id, frame_id_to_frame)
|
||||
|
||||
try:
|
||||
main_debugger.send_caught_exception_stack(thread, arg, id(frame))
|
||||
self.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
|
||||
self.do_wait_suspend(thread, frame, event, arg)
|
||||
main_debugger.send_caught_exception_stack_proceeded(thread)
|
||||
|
||||
finally:
|
||||
pydevd_vars.remove_additional_frame_by_id(thread_id)
|
||||
except KeyboardInterrupt as e:
|
||||
raise e
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
main_debugger.set_trace_for_frame_and_parents(frame)
|
||||
finally:
|
||||
# Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
|
||||
remove_exception_from_frame(frame)
|
||||
# Clear some local variables...
|
||||
frame = None
|
||||
trace_obj = None
|
||||
initial_trace_obj = None
|
||||
check_trace_obj = None
|
||||
f = None
|
||||
frame_id_to_frame = None
|
||||
main_debugger = None
|
||||
thread = None
|
||||
|
||||
def get_func_name(self, frame):
|
||||
code_obj = frame.f_code
|
||||
func_name = code_obj.co_name
|
||||
@@ -510,9 +516,10 @@ class PyDBFrame:
|
||||
|
||||
if is_exception_event:
|
||||
if has_exception_breakpoints:
|
||||
should_stop, frame = self.should_stop_on_exception(frame, event, arg)
|
||||
should_stop, frame = should_stop_on_exception(
|
||||
self._args, frame, event, arg)
|
||||
if should_stop:
|
||||
self.handle_exception(frame, event, arg)
|
||||
handle_exception(self._args, frame, event, arg)
|
||||
# No need to reset frame.f_trace to keep the same trace function.
|
||||
return self.trace_dispatch
|
||||
is_line = False
|
||||
@@ -580,7 +587,7 @@ class PyDBFrame:
|
||||
|
||||
if can_skip:
|
||||
if plugin_manager is not None and main_debugger.has_plugin_line_breaks:
|
||||
can_skip = not plugin_manager.can_not_skip(main_debugger, self, frame, info)
|
||||
can_skip = not plugin_manager.can_not_skip(main_debugger, frame, info)
|
||||
|
||||
# CMD_STEP_OVER = 108
|
||||
if can_skip and main_debugger.show_return_values and info.pydev_step_cmd == 108 and frame.f_back is info.pydev_step_stop:
|
||||
@@ -679,7 +686,7 @@ class PyDBFrame:
|
||||
elif step_cmd == CMD_SMART_STEP_INTO and (frame.f_back is smart_stop_frame and is_within_context):
|
||||
stop = False
|
||||
elif plugin_manager is not None and main_debugger.has_plugin_line_breaks:
|
||||
result = plugin_manager.get_breakpoint(main_debugger, self, frame, event, self._args)
|
||||
result = plugin_manager.get_breakpoint(main_debugger, frame, event, self._args)
|
||||
if result:
|
||||
exist_result = True
|
||||
flag, breakpoint, new_frame, bp_type = result
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import linecache
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
@@ -7,23 +6,19 @@ from os.path import splitext, basename
|
||||
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydevd_bundle import pydevd_vars
|
||||
from _pydevd_bundle.pydevd_additional_thread_info_regular import \
|
||||
set_additional_thread_info
|
||||
from _pydevd_bundle.pydevd_breakpoints import get_exception_breakpoint, \
|
||||
stop_on_unhandled_exception
|
||||
from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception
|
||||
from _pydevd_bundle.pydevd_bytecode_utils import find_last_call_name, \
|
||||
find_last_func_call_order
|
||||
from _pydevd_bundle.pydevd_comm_constants import CMD_STEP_OVER, CMD_SMART_STEP_INTO, \
|
||||
CMD_SET_BREAK, CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_INTO_COROUTINE, \
|
||||
CMD_STEP_CAUGHT_EXCEPTION
|
||||
CMD_SET_BREAK, CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_INTO_COROUTINE
|
||||
from _pydevd_bundle.pydevd_constants import get_current_thread_id, PYDEVD_TOOL_NAME, \
|
||||
STATE_RUN, STATE_SUSPEND
|
||||
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE
|
||||
from _pydevd_bundle.pydevd_frame import handle_breakpoint_condition, \
|
||||
handle_breakpoint_expression, DEBUG_START, DEBUG_START_PY3K, IGNORE_EXCEPTION_TAG
|
||||
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, \
|
||||
remove_exception_from_frame, ignore_exception_trace, just_raised
|
||||
handle_breakpoint_expression, DEBUG_START, DEBUG_START_PY3K, \
|
||||
should_stop_on_exception, handle_exception
|
||||
from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads
|
||||
from pydevd_file_utils import NORM_PATHS_AND_BASE_CONTAINER, \
|
||||
get_abs_path_real_path_and_base_from_frame
|
||||
@@ -201,7 +196,7 @@ class PyStartCallback(PEP669CallbackBase):
|
||||
if can_skip:
|
||||
if plugin_manager is not None and self.py_db.has_plugin_line_breaks:
|
||||
can_skip = not plugin_manager.can_not_skip(
|
||||
self.py_db, self, frame, info)
|
||||
self.py_db, frame, info)
|
||||
|
||||
# CMD_STEP_OVER = 108
|
||||
if (can_skip and self.py_db.show_return_values
|
||||
@@ -465,9 +460,6 @@ class PyLineCallback(PEP669CallbackBase):
|
||||
|
||||
|
||||
class PyRaiseCallback(PEP669CallbackBase):
|
||||
filename_to_lines_where_exceptions_are_ignored = {}
|
||||
filename_to_stat_info = {}
|
||||
|
||||
_top_level_frame = None
|
||||
|
||||
def _get_top_level_frame(self):
|
||||
@@ -502,9 +494,15 @@ class PyRaiseCallback(PEP669CallbackBase):
|
||||
or self.py_db.has_plugin_exception_breaks
|
||||
or self.py_db.stop_on_failed_tests)
|
||||
if has_exception_breakpoints:
|
||||
should_stop, frame = self.should_stop_on_exception(self.frame, exc_info)
|
||||
args = (
|
||||
self.py_db, self._get_filename(frame),
|
||||
self._get_additional_info(self.thread), self.thread, global_cache_skips,
|
||||
global_cache_frame_skips
|
||||
)
|
||||
should_stop, frame = should_stop_on_exception(
|
||||
args, self.frame, 'exception', exc_info)
|
||||
if should_stop:
|
||||
self.handle_exception(frame, 'exception', exc_info)
|
||||
handle_exception(args, frame, 'exception', exc_info)
|
||||
|
||||
def _stop_on_unhandled_exception(self, exc_info):
|
||||
additional_info = self._get_additional_info(self.thread)
|
||||
@@ -513,212 +511,6 @@ class PyRaiseCallback(PEP669CallbackBase):
|
||||
stop_on_unhandled_exception(self.py_db, self.thread, additional_info,
|
||||
exc_info)
|
||||
|
||||
# XXX: Copy-paste from `PyDBFrame`. This method should be factored out. Plugins
|
||||
# are not supported.
|
||||
def should_stop_on_exception(self, frame, arg):
|
||||
thread = self.thread
|
||||
info = self._get_additional_info(thread)
|
||||
should_stop = False
|
||||
|
||||
# STATE_SUSPEND = 2
|
||||
if info.pydev_state == 2:
|
||||
return should_stop, frame
|
||||
|
||||
exception, value, trace = arg
|
||||
|
||||
if trace is not None and hasattr(trace, 'tb_next'):
|
||||
exception_breakpoint = get_exception_breakpoint(
|
||||
exception, self.py_db.break_on_caught_exceptions)
|
||||
|
||||
if exception_breakpoint is not None:
|
||||
if exception_breakpoint.condition is not None:
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
eval_result = handle_breakpoint_condition(self.py_db, info, exception_breakpoint, frame)
|
||||
remove_exception_from_frame(frame)
|
||||
if not eval_result:
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.ignore_libraries:
|
||||
if not self.py_db.is_exception_trace_in_project_scope(trace):
|
||||
return False, frame
|
||||
|
||||
if ignore_exception_trace(trace):
|
||||
return False, frame
|
||||
|
||||
was_just_raised = just_raised(trace)
|
||||
if was_just_raised:
|
||||
|
||||
if self.py_db.skip_on_exceptions_thrown_in_same_context:
|
||||
# Option: Don't break if an exception is caught in the same function from which it is thrown
|
||||
return False, frame
|
||||
|
||||
if exception_breakpoint.notify_on_first_raise_only:
|
||||
if self.py_db.skip_on_exceptions_thrown_in_same_context:
|
||||
# In this case we never stop if it was just raised, so, to know if it was the first we
|
||||
# need to check if we're in the 2nd method.
|
||||
if not was_just_raised and not just_raised(trace.tb_next):
|
||||
return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception
|
||||
|
||||
else:
|
||||
if not was_just_raised and not self.py_db.is_top_level_trace_in_project_scope(trace):
|
||||
return False, frame # I.e.: we stop only when it was just raised
|
||||
|
||||
# If it got here we should stop.
|
||||
should_stop = True
|
||||
try:
|
||||
info.pydev_message = exception_breakpoint.qname
|
||||
except:
|
||||
info.pydev_message = exception_breakpoint.qname.encode('utf-8')
|
||||
|
||||
# Always add exception to frame (must remove later after we proceed).
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
|
||||
info.pydev_message = "python-%s" % info.pydev_message
|
||||
|
||||
if should_stop:
|
||||
if exception_breakpoint is not None and exception_breakpoint.expression is not None:
|
||||
handle_breakpoint_expression(exception_breakpoint, info, frame)
|
||||
|
||||
return should_stop, frame
|
||||
|
||||
# XXX: Copy-paste from `PyDBFrame`. This method should be factored out.
|
||||
def handle_exception(self, frame, event, arg):
|
||||
try:
|
||||
# We have 3 things in arg: exception type, description, traceback object
|
||||
trace_obj = arg[2]
|
||||
|
||||
initial_trace_obj = trace_obj
|
||||
if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
|
||||
# I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
|
||||
pass
|
||||
else:
|
||||
# Get the trace_obj from where the exception was raised...
|
||||
while trace_obj.tb_next is not None:
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
if self.py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception \
|
||||
and not self.py_db.stop_on_failed_tests:
|
||||
|
||||
for check_trace_obj in (initial_trace_obj, trace_obj):
|
||||
filename = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)[1]
|
||||
|
||||
filename_to_lines_where_exceptions_are_ignored = self.filename_to_lines_where_exceptions_are_ignored
|
||||
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if lines_ignored is None:
|
||||
lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}
|
||||
|
||||
try:
|
||||
curr_stat = os.stat(filename)
|
||||
curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
|
||||
except:
|
||||
curr_stat = None
|
||||
|
||||
last_stat = self.filename_to_stat_info.get(filename)
|
||||
if last_stat != curr_stat:
|
||||
self.filename_to_stat_info[filename] = curr_stat
|
||||
lines_ignored.clear()
|
||||
try:
|
||||
linecache.checkcache(filename)
|
||||
except:
|
||||
# Jython 2.1
|
||||
linecache.checkcache()
|
||||
|
||||
from_user_input = self.py_db.filename_to_lines_where_exceptions_are_ignored.get(filename)
|
||||
if from_user_input:
|
||||
merged = {}
|
||||
merged.update(lines_ignored)
|
||||
# Override what we have with the related entries that the user entered
|
||||
merged.update(from_user_input)
|
||||
else:
|
||||
merged = lines_ignored
|
||||
|
||||
exc_lineno = check_trace_obj.tb_lineno
|
||||
|
||||
# print ('lines ignored', lines_ignored)
|
||||
# print ('user input', from_user_input)
|
||||
# print ('merged', merged, 'curr', exc_lineno)
|
||||
|
||||
if exc_lineno not in merged: # Note: check on merged but update lines_ignored.
|
||||
try:
|
||||
line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
|
||||
except:
|
||||
# Jython 2.1
|
||||
line = linecache.getline(filename, exc_lineno)
|
||||
|
||||
if IGNORE_EXCEPTION_TAG.match(line) is not None:
|
||||
lines_ignored[exc_lineno] = 1
|
||||
return
|
||||
else:
|
||||
# Put in the cache saying not to ignore
|
||||
lines_ignored[exc_lineno] = 0
|
||||
else:
|
||||
# Ok, dict has it already cached, so, let's check it...
|
||||
if merged.get(exc_lineno, 0):
|
||||
return
|
||||
|
||||
thread = self.thread
|
||||
|
||||
try:
|
||||
frame_id_to_frame = {}
|
||||
frame_id_to_frame[id(frame)] = frame
|
||||
f = trace_obj.tb_frame
|
||||
while f is not None:
|
||||
frame_id_to_frame[id(f)] = f
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
thread_id = get_current_thread_id(thread)
|
||||
|
||||
if self.py_db.stop_on_failed_tests:
|
||||
# Our goal is to find the deepest frame in stack that still belongs to the project and stop there.
|
||||
f = trace_obj.tb_frame
|
||||
while f:
|
||||
abs_path, _, _ = get_abs_path_real_path_and_base_from_frame(f)
|
||||
if self.py_db.in_project_scope(abs_path):
|
||||
frame = f
|
||||
break
|
||||
f = f.f_back
|
||||
f = None
|
||||
|
||||
trace_obj = initial_trace_obj
|
||||
while trace_obj:
|
||||
if trace_obj.tb_frame is frame:
|
||||
break
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
add_exception_to_frame(frame, (arg[0], arg[1], trace_obj))
|
||||
|
||||
pydevd_vars.add_additional_frame_by_id(thread_id, frame_id_to_frame)
|
||||
|
||||
try:
|
||||
self.py_db.send_caught_exception_stack(thread, arg, id(frame))
|
||||
self.py_db.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
|
||||
self.py_db.do_wait_suspend(thread, frame, event, arg)
|
||||
self.py_db.send_caught_exception_stack_proceeded(thread)
|
||||
|
||||
finally:
|
||||
pydevd_vars.remove_additional_frame_by_id(thread_id)
|
||||
except KeyboardInterrupt as e:
|
||||
raise e
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
self.py_db.set_trace_for_frame_and_parents(frame)
|
||||
finally:
|
||||
# Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
|
||||
remove_exception_from_frame(frame)
|
||||
# Clear some local variables...
|
||||
frame = None
|
||||
trace_obj = None
|
||||
initial_trace_obj = None
|
||||
check_trace_obj = None
|
||||
f = None
|
||||
frame_id_to_frame = None
|
||||
main_debugger = None
|
||||
thread = None
|
||||
|
||||
|
||||
class PyReturnCallback(PEP669CallbackBase):
|
||||
def __call__(self, code, instruction_offset, retval):
|
||||
|
||||
@@ -10,7 +10,7 @@ def remove_exception_breakpoint(plugin, pydb, type, exception):
|
||||
def get_breakpoints(plugin, pydb):
|
||||
return None
|
||||
|
||||
def can_not_skip(plugin, pydb, pydb_frame, frame, info):
|
||||
def can_not_skip(plugin, pydb, frame, info):
|
||||
return False
|
||||
|
||||
def has_exception_breaks(plugin):
|
||||
@@ -28,13 +28,13 @@ def cmd_step_over(plugin, pydb, frame, event, args, stop_info, stop):
|
||||
def stop(plugin, pydb, frame, event, args, stop_info, arg, step_cmd):
|
||||
return False
|
||||
|
||||
def get_breakpoint(plugin, pydb, pydb_frame, frame, event, args):
|
||||
def get_breakpoint(plugin, pydb, frame, event, args):
|
||||
return None
|
||||
|
||||
def suspend(plugin, pydb, thread, frame):
|
||||
return None
|
||||
|
||||
def exception_break(plugin, pydb, pydb_frame, frame, args, arg):
|
||||
def exception_break(plugin, pydb, frame, args, arg):
|
||||
return None
|
||||
|
||||
def change_variable(plugin, frame, attr, expression):
|
||||
|
||||
@@ -238,7 +238,7 @@ def get_func_code_info_py(code_obj) -> FuncCodeInfo:
|
||||
|
||||
|
||||
# noinspection DuplicatedCode
|
||||
cdef PyObject * get_bytecode_while_frame_eval(PyFrameObject * frame_obj, int exc):
|
||||
cdef PyObject * get_bytecode_while_frame_eval(PyFrameObject * frame_obj, int exc) noexcept:
|
||||
'''
|
||||
This function makes the actual evaluation and changes the bytecode to a version
|
||||
where programmatic breakpoints are added.
|
||||
|
||||
@@ -238,7 +238,7 @@ def get_func_code_info_py(code_obj) -> FuncCodeInfo:
|
||||
|
||||
|
||||
# noinspection DuplicatedCode
|
||||
cdef PyObject * get_bytecode_while_frame_eval(PyThreadState *tstate, PyFrameObject * frame_obj, int exc):
|
||||
cdef PyObject * get_bytecode_while_frame_eval(PyThreadState *tstate, PyFrameObject * frame_obj, int exc) noexcept:
|
||||
'''
|
||||
This function makes the actual evaluation and changes the bytecode to a version
|
||||
where programmatic breakpoints are added.
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -333,7 +333,7 @@ def _is_django_exception_break_context(frame):
|
||||
# Django Step Commands
|
||||
#=======================================================================================================================
|
||||
|
||||
def can_not_skip(plugin, main_debugger, pydb_frame, frame, info):
|
||||
def can_not_skip(plugin, main_debugger, frame, info):
|
||||
return main_debugger.django_breakpoints and _is_django_render_call(frame)
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ def stop(plugin, main_debugger, frame, event, args, stop_info, arg, step_cmd):
|
||||
return False
|
||||
|
||||
|
||||
def get_breakpoint(plugin, main_debugger, pydb_frame, frame, event, args):
|
||||
def get_breakpoint(plugin, main_debugger, frame, event, args):
|
||||
main_debugger = args[0]
|
||||
filename = args[1]
|
||||
info = args[2]
|
||||
@@ -424,7 +424,7 @@ def suspend(plugin, main_debugger, thread, frame, bp_type):
|
||||
return suspend_django(main_debugger, thread, frame)
|
||||
return None
|
||||
|
||||
def exception_break(plugin, main_debugger, pydb_frame, frame, args, arg):
|
||||
def exception_break(plugin, main_debugger, frame, args, arg):
|
||||
main_debugger = args[0]
|
||||
thread = args[3]
|
||||
exception, value, trace = arg
|
||||
|
||||
@@ -230,7 +230,7 @@ def has_line_breaks(plugin):
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_not_skip(plugin, pydb, pydb_frame, frame, info):
|
||||
def can_not_skip(plugin, pydb, frame, info):
|
||||
if pydb.jinja2_breakpoints and _is_jinja2_render_call(frame):
|
||||
filename = _get_jinja2_template_filename(frame)
|
||||
jinja2_breakpoints_for_file = pydb.jinja2_breakpoints.get(filename)
|
||||
@@ -325,7 +325,7 @@ def stop(plugin, pydb, frame, event, args, stop_info, arg, step_cmd):
|
||||
return False
|
||||
|
||||
|
||||
def get_breakpoint(plugin, pydb, pydb_frame, frame, event, args):
|
||||
def get_breakpoint(plugin, pydb, frame, event, args):
|
||||
pydb= args[0]
|
||||
filename = args[1]
|
||||
info = args[2]
|
||||
@@ -356,7 +356,7 @@ def suspend(plugin, pydb, thread, frame, bp_type):
|
||||
return None
|
||||
|
||||
|
||||
def exception_break(plugin, pydb, pydb_frame, frame, args, arg):
|
||||
def exception_break(plugin, pydb, frame, args, arg):
|
||||
pydb = args[0]
|
||||
thread = args[3]
|
||||
exception, value, trace = arg
|
||||
@@ -378,7 +378,7 @@ def exception_break(plugin, pydb, pydb_frame, frame, args, arg):
|
||||
name = frame.f_code.co_name
|
||||
if name in ('template', 'top-level template code', '<module>') or name.startswith('block '):
|
||||
#Jinja2 translates exception info and creates fake frame on his own
|
||||
pydb_frame.set_suspend(thread, CMD_ADD_EXCEPTION_BREAK)
|
||||
pydb.set_suspend(thread, CMD_ADD_EXCEPTION_BREAK)
|
||||
add_exception_to_frame(frame, (exception, value, trace))
|
||||
thread.additional_info.suspend_type = JINJA2_SUSPEND
|
||||
thread.additional_info.pydev_message = str(exception_type)
|
||||
|
||||
Reference in New Issue
Block a user