mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Allow configuring whether the debugger should stop/print errors when there's an exception evaluating a breakpoint condition. Fixes #853 (#876)
* Allow configuring whether the debugger should stop/print errors when there's an exception evaluating a breakpoint condition. Fixes #853 * Temporarily remove CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION configuration (needs test fixes to be applied). * Fix linting.
This commit is contained in:
parent
8fd2c74cd4
commit
fcdb060b76
8 changed files with 179 additions and 56 deletions
|
|
@ -17,7 +17,7 @@ class ExceptionBreakpoint(object):
|
|||
notify_on_first_raise_only,
|
||||
ignore_libraries
|
||||
):
|
||||
exctype = _get_class(qname)
|
||||
exctype = get_exception_class(qname)
|
||||
self.qname = qname
|
||||
if exctype is not None:
|
||||
self.name = exctype.__name__
|
||||
|
|
@ -156,7 +156,7 @@ def stop_on_unhandled_exception(py_db, thread, additional_info, arg):
|
|||
py_db.stop_on_unhandled_exception(thread, frame, frames_byid, arg)
|
||||
|
||||
|
||||
def _get_class(kls):
|
||||
def get_exception_class(kls):
|
||||
if IS_PY24 and "BaseException" == kls:
|
||||
kls = "Exception"
|
||||
|
||||
|
|
|
|||
|
|
@ -185,6 +185,8 @@ CMD_STOP_ON_START = 154
|
|||
# When the debugger is stopped in an exception, this command will provide the details of the current exception (in the current thread).
|
||||
CMD_GET_EXCEPTION_DETAILS = 155
|
||||
|
||||
CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION = 156
|
||||
|
||||
CMD_REDIRECT_OUTPUT = 200
|
||||
CMD_GET_NEXT_STATEMENT_TARGETS = 201
|
||||
CMD_SET_PROJECT_ROOTS = 202
|
||||
|
|
@ -252,6 +254,7 @@ ID_TO_MEANING = {
|
|||
'153': 'CMD_THREAD_DUMP_TO_STDERR',
|
||||
'154': 'CMD_STOP_ON_START',
|
||||
'155': 'CMD_GET_EXCEPTION_DETAILS',
|
||||
'156': 'CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION',
|
||||
|
||||
'200': 'CMD_REDIRECT_OUTPUT',
|
||||
'201': 'CMD_GET_NEXT_STATEMENT_TARGETS',
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ try:
|
|||
from inspect import CO_GENERATOR
|
||||
except:
|
||||
CO_GENERATOR = 0
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY2
|
||||
|
||||
try:
|
||||
from _pydevd_bundle.pydevd_signature import send_signature_call_trace, send_signature_return_trace
|
||||
|
|
@ -51,34 +52,37 @@ def handle_breakpoint_condition(py_db, info, breakpoint, new_frame):
|
|||
return False
|
||||
|
||||
return eval(condition, new_frame.f_globals, new_frame.f_locals)
|
||||
|
||||
except:
|
||||
if type(condition) != type(''):
|
||||
if hasattr(condition, 'encode'):
|
||||
except Exception as e:
|
||||
if IS_PY2:
|
||||
# Must be bytes on py2.
|
||||
if isinstance(condition, unicode):
|
||||
condition = condition.encode('utf-8')
|
||||
|
||||
msg = 'Error while evaluating expression: %s\n' % (condition,)
|
||||
sys.stderr.write(msg)
|
||||
traceback.print_exc()
|
||||
if not py_db.suspend_on_breakpoint_exception:
|
||||
return False
|
||||
else:
|
||||
if not isinstance(e, py_db.skip_print_breakpoint_exception):
|
||||
sys.stderr.write('Error while evaluating expression: %s\n' % (condition,))
|
||||
|
||||
etype, value, tb = sys.exc_info()
|
||||
traceback.print_exception(etype, value, tb.tb_next)
|
||||
|
||||
if not isinstance(e, py_db.skip_suspend_on_breakpoint_exception):
|
||||
try:
|
||||
# add exception_type and stacktrace into thread additional info
|
||||
etype, value, tb = sys.exc_info()
|
||||
try:
|
||||
error = ''.join(traceback.format_exception_only(etype, value))
|
||||
stack = traceback.extract_stack(f=tb.tb_frame.f_back)
|
||||
error = ''.join(traceback.format_exception_only(etype, value))
|
||||
stack = traceback.extract_stack(f=tb.tb_frame.f_back)
|
||||
|
||||
# On self.set_suspend(thread, CMD_SET_BREAK) this info will be
|
||||
# sent to the client.
|
||||
info.conditional_breakpoint_exception = \
|
||||
('Condition:\n' + condition + '\n\nError:\n' + error, stack)
|
||||
finally:
|
||||
etype, value, tb = None, None, None
|
||||
# On self.set_suspend(thread, CMD_SET_BREAK) this info will be
|
||||
# sent to the client.
|
||||
info.conditional_breakpoint_exception = \
|
||||
('Condition:\n' + condition + '\n\nError:\n' + error, stack)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
finally:
|
||||
etype, value, tb = None, None, None
|
||||
|
||||
|
||||
def handle_breakpoint_expression(breakpoint, info, new_frame):
|
||||
|
|
@ -619,7 +623,7 @@ class PyDBFrame:
|
|||
#
|
||||
# As for lamdba, as it only has a single statement, it's not interesting to trace
|
||||
# its call and later its line event as they're usually in the same line.
|
||||
|
||||
|
||||
# No need to reset frame.f_trace to keep the same trace function.
|
||||
return self.trace_dispatch
|
||||
|
||||
|
|
|
|||
|
|
@ -6,26 +6,27 @@ from _pydev_bundle import pydev_log
|
|||
from _pydevd_bundle import pydevd_traceproperty, pydevd_dont_trace, pydevd_utils
|
||||
import pydevd_tracing
|
||||
import pydevd_file_utils
|
||||
from _pydevd_bundle.pydevd_breakpoints import LineBreakpoint
|
||||
from _pydevd_bundle.pydevd_comm import CMD_RUN, CMD_VERSION, CMD_LIST_THREADS, CMD_THREAD_KILL, InternalTerminateThread, \
|
||||
CMD_THREAD_SUSPEND, pydevd_find_thread_by_id, CMD_THREAD_RUN, InternalRunThread, CMD_STEP_INTO, CMD_STEP_OVER, \
|
||||
CMD_STEP_RETURN, CMD_STEP_INTO_MY_CODE, InternalStepThread, CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT, \
|
||||
CMD_SMART_STEP_INTO, InternalSetNextStatementThread, CMD_RELOAD_CODE, ReloadCodeCommand, CMD_CHANGE_VARIABLE, \
|
||||
InternalChangeVariable, CMD_GET_VARIABLE, InternalGetVariable, CMD_GET_ARRAY, InternalGetArray, CMD_GET_COMPLETIONS, \
|
||||
InternalGetCompletions, CMD_GET_FRAME, InternalGetFrame, CMD_SET_BREAK, file_system_encoding, CMD_REMOVE_BREAK, \
|
||||
CMD_EVALUATE_EXPRESSION, CMD_EXEC_EXPRESSION, InternalEvaluateExpression, CMD_CONSOLE_EXEC, InternalConsoleExec, \
|
||||
CMD_SET_PY_EXCEPTION, CMD_GET_FILE_CONTENTS, CMD_SET_PROPERTY_TRACE, CMD_ADD_EXCEPTION_BREAK, \
|
||||
CMD_REMOVE_EXCEPTION_BREAK, CMD_LOAD_SOURCE, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK, \
|
||||
CMD_EVALUATE_CONSOLE_EXPRESSION, InternalEvaluateConsoleExpression, InternalConsoleGetCompletions, \
|
||||
CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE, \
|
||||
CMD_SHOW_RETURN_VALUES, ID_TO_MEANING, CMD_GET_DESCRIPTION, InternalGetDescription, InternalLoadFullValue, \
|
||||
CMD_LOAD_FULL_VALUE, CMD_REDIRECT_OUTPUT, CMD_GET_NEXT_STATEMENT_TARGETS, InternalGetNextStatementTargets, CMD_SET_PROJECT_ROOTS, \
|
||||
CMD_GET_THREAD_STACK, CMD_THREAD_DUMP_TO_STDERR, CMD_STOP_ON_START, CMD_GET_EXCEPTION_DETAILS, NetCommand,\
|
||||
CMD_SET_PROTOCOL
|
||||
from _pydevd_bundle.pydevd_constants import get_thread_id, IS_PY3K, DebugInfoHolder, dict_keys, STATE_RUN, \
|
||||
NEXT_VALUE_SEPARATOR, IS_WINDOWS
|
||||
from _pydevd_bundle.pydevd_breakpoints import LineBreakpoint, get_exception_class
|
||||
from _pydevd_bundle.pydevd_comm import (CMD_RUN, CMD_VERSION, CMD_LIST_THREADS, CMD_THREAD_KILL, InternalTerminateThread,
|
||||
CMD_THREAD_SUSPEND, pydevd_find_thread_by_id, CMD_THREAD_RUN, InternalRunThread, CMD_STEP_INTO, CMD_STEP_OVER,
|
||||
CMD_STEP_RETURN, CMD_STEP_INTO_MY_CODE, InternalStepThread, CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT,
|
||||
CMD_SMART_STEP_INTO, InternalSetNextStatementThread, CMD_RELOAD_CODE, ReloadCodeCommand, CMD_CHANGE_VARIABLE,
|
||||
InternalChangeVariable, CMD_GET_VARIABLE, InternalGetVariable, CMD_GET_ARRAY, InternalGetArray, CMD_GET_COMPLETIONS,
|
||||
InternalGetCompletions, CMD_GET_FRAME, InternalGetFrame, CMD_SET_BREAK, file_system_encoding, CMD_REMOVE_BREAK,
|
||||
CMD_EVALUATE_EXPRESSION, CMD_EXEC_EXPRESSION, InternalEvaluateExpression, CMD_CONSOLE_EXEC, InternalConsoleExec,
|
||||
CMD_SET_PY_EXCEPTION, CMD_GET_FILE_CONTENTS, CMD_SET_PROPERTY_TRACE, CMD_ADD_EXCEPTION_BREAK,
|
||||
CMD_REMOVE_EXCEPTION_BREAK, CMD_LOAD_SOURCE, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK,
|
||||
CMD_EVALUATE_CONSOLE_EXPRESSION, InternalEvaluateConsoleExpression, InternalConsoleGetCompletions,
|
||||
CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE,
|
||||
CMD_SHOW_RETURN_VALUES, ID_TO_MEANING, CMD_GET_DESCRIPTION, InternalGetDescription, InternalLoadFullValue,
|
||||
CMD_LOAD_FULL_VALUE, CMD_REDIRECT_OUTPUT, CMD_GET_NEXT_STATEMENT_TARGETS, InternalGetNextStatementTargets, CMD_SET_PROJECT_ROOTS,
|
||||
CMD_GET_THREAD_STACK, CMD_THREAD_DUMP_TO_STDERR, CMD_STOP_ON_START, CMD_GET_EXCEPTION_DETAILS, NetCommand,
|
||||
CMD_SET_PROTOCOL, CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION)
|
||||
from _pydevd_bundle.pydevd_constants import (get_thread_id, IS_PY3K, DebugInfoHolder, dict_keys, STATE_RUN,
|
||||
NEXT_VALUE_SEPARATOR, IS_WINDOWS)
|
||||
from _pydevd_bundle.pydevd_additional_thread_info import set_additional_thread_info
|
||||
from _pydev_imps._pydev_saved_modules import threading
|
||||
import json
|
||||
|
||||
def process_net_command(py_db, cmd_id, seq, text):
|
||||
'''Processes a command received from the Java side
|
||||
|
|
@ -819,6 +820,19 @@ def process_net_command(py_db, cmd_id, seq, text):
|
|||
|
||||
elif cmd_id == CMD_STOP_ON_START:
|
||||
py_db.stop_on_start = text.strip() in ('True', 'true', '1')
|
||||
|
||||
elif cmd_id == CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION:
|
||||
# Expected to receive a json string as:
|
||||
# {
|
||||
# 'skip_suspend_on_breakpoint_exception': [<exception names where we should suspend>]
|
||||
# 'skip_print_breakpoint_exception': [<exception names where we should print>]
|
||||
# }
|
||||
msg = json.loads(text.strip())
|
||||
py_db.skip_suspend_on_breakpoint_exception = tuple(
|
||||
get_exception_class(x) for x in msg.get('skip_suspend_on_breakpoint_exception', ()))
|
||||
|
||||
py_db.skip_print_breakpoint_exception = tuple(
|
||||
get_exception_class(x) for x in msg.get('skip_print_breakpoint_exception', ()))
|
||||
|
||||
elif cmd_id == CMD_GET_EXCEPTION_DETAILS:
|
||||
thread_id = text
|
||||
|
|
|
|||
|
|
@ -256,9 +256,10 @@ class PyDB:
|
|||
self.skip_on_exceptions_thrown_in_same_context = False
|
||||
self.ignore_exceptions_thrown_in_lines_with_ignore_exception = True
|
||||
|
||||
# Suspend debugger even if breakpoint condition raises an exception
|
||||
SUSPEND_ON_BREAKPOINT_EXCEPTION = True
|
||||
self.suspend_on_breakpoint_exception = SUSPEND_ON_BREAKPOINT_EXCEPTION
|
||||
# Suspend debugger even if breakpoint condition raises an exception.
|
||||
# May be changed with CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION.
|
||||
self.skip_suspend_on_breakpoint_exception = () # By default suspend on any Exception.
|
||||
self.skip_print_breakpoint_exception = () # By default print on any Exception.
|
||||
|
||||
# By default user can step into properties getter/setter/deleter methods
|
||||
self.disable_property_trace = False
|
||||
|
|
@ -711,22 +712,21 @@ class PyDB:
|
|||
thread.stop_reason = stop_reason
|
||||
|
||||
# If conditional breakpoint raises any exception during evaluation send details to Java
|
||||
if stop_reason == CMD_SET_BREAK and self.suspend_on_breakpoint_exception:
|
||||
self._send_breakpoint_condition_exception(thread)
|
||||
if stop_reason == CMD_SET_BREAK and info.conditional_breakpoint_exception is not None:
|
||||
conditional_breakpoint_exception_tuple = info.conditional_breakpoint_exception
|
||||
info.conditional_breakpoint_exception = None
|
||||
self._send_breakpoint_condition_exception(thread, conditional_breakpoint_exception_tuple)
|
||||
|
||||
|
||||
def _send_breakpoint_condition_exception(self, thread):
|
||||
def _send_breakpoint_condition_exception(self, thread, conditional_breakpoint_exception_tuple):
|
||||
"""If conditional breakpoint raises an exception during evaluation
|
||||
send exception details to java
|
||||
"""
|
||||
thread_id = get_thread_id(thread)
|
||||
conditional_breakpoint_exception_tuple = thread.additional_info.conditional_breakpoint_exception
|
||||
# conditional_breakpoint_exception_tuple - should contain 2 values (exception_type, stacktrace)
|
||||
if conditional_breakpoint_exception_tuple and len(conditional_breakpoint_exception_tuple) == 2:
|
||||
exc_type, stacktrace = conditional_breakpoint_exception_tuple
|
||||
int_cmd = InternalGetBreakpointException(thread_id, exc_type, stacktrace)
|
||||
# Reset the conditional_breakpoint_exception details to None
|
||||
thread.additional_info.conditional_breakpoint_exception = None
|
||||
self.post_internal_command(int_cmd, thread_id)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from collections import namedtuple
|
||||
from contextlib import contextmanager
|
||||
import json
|
||||
try:
|
||||
from urllib import quote, quote_plus, unquote_plus
|
||||
except ImportError:
|
||||
|
|
@ -74,6 +75,7 @@ CMD_GET_THREAD_STACK = 152
|
|||
CMD_THREAD_DUMP_TO_STDERR = 153 # This is mostly for unit-tests to diagnose errors on ci.
|
||||
CMD_STOP_ON_START = 154
|
||||
CMD_GET_EXCEPTION_DETAILS = 155
|
||||
CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION = 156
|
||||
|
||||
CMD_REDIRECT_OUTPUT = 200
|
||||
CMD_GET_NEXT_STATEMENT_TARGETS = 201
|
||||
|
|
@ -736,29 +738,37 @@ class AbstractWriterThread(threading.Thread):
|
|||
|
||||
def write_version(self):
|
||||
from _pydevd_bundle.pydevd_constants import IS_WINDOWS
|
||||
self.write("501\t%s\t1.0\t%s\tID" % (self.next_seq(), 'WINDOWS' if IS_WINDOWS else 'UNIX'))
|
||||
self.write("%s\t%s\t1.0\t%s\tID" % (CMD_VERSION, self.next_seq(), 'WINDOWS' if IS_WINDOWS else 'UNIX'))
|
||||
|
||||
def get_main_filename(self):
|
||||
return self.TEST_FILE
|
||||
|
||||
def write_add_breakpoint(self, line, func, filename=None, hit_condition=None, is_logpoint=False, suspend_policy=None):
|
||||
def write_add_breakpoint(self, line, func, filename=None, hit_condition=None, is_logpoint=False, suspend_policy=None, condition=None):
|
||||
'''
|
||||
@param line: starts at 1
|
||||
'''
|
||||
if filename is None:
|
||||
filename = self.get_main_filename()
|
||||
breakpoint_id = self.next_breakpoint_id()
|
||||
if hit_condition is None and not is_logpoint and suspend_policy is None:
|
||||
if hit_condition is None and not is_logpoint and suspend_policy is None and condition is None:
|
||||
# Format kept for backward compatibility tests
|
||||
self.write("%s\t%s\t%s\t%s\t%s\t%s\t%s\tNone\tNone" % (
|
||||
CMD_SET_BREAK, self.next_seq(), breakpoint_id, 'python-line', filename, line, func))
|
||||
else:
|
||||
# Format: breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint, suspend_policy
|
||||
self.write("%s\t%s\t%s\t%s\t%s\t%s\t%s\tNone\tNone\t%s\t%s\t%s" % (
|
||||
CMD_SET_BREAK, self.next_seq(), breakpoint_id, 'python-line', filename, line, func, hit_condition, is_logpoint, suspend_policy))
|
||||
self.write("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\tNone\t%s\t%s\t%s" % (
|
||||
CMD_SET_BREAK, self.next_seq(), breakpoint_id, 'python-line', filename, line, func, condition, hit_condition, is_logpoint, suspend_policy))
|
||||
self.log.append('write_add_breakpoint: %s line: %s func: %s' % (breakpoint_id, line, func))
|
||||
return breakpoint_id
|
||||
|
||||
def write_suspend_on_breakpoint_exception(self, skip_suspend_on_breakpoint_exception=('all',), skip_print_breakpoint_exception=('all',)):
|
||||
self.write("%s\t%s\t%s" % (CMD_SUSPEND_ON_BREAKPOINT_EXCEPTION, self.next_seq(),
|
||||
json.dumps(dict(
|
||||
skip_suspend_on_breakpoint_exception=skip_suspend_on_breakpoint_exception,
|
||||
skip_print_breakpoint_exception=skip_print_breakpoint_exception
|
||||
))
|
||||
))
|
||||
|
||||
def write_stop_on_start(self, stop=True):
|
||||
self.write("%s\t%s\t%s" % (CMD_STOP_ON_START, self.next_seq(), stop))
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
def Call():
|
||||
for i in range(10): # break here
|
||||
last_i = i
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Call()
|
||||
print('TEST SUCEEDED!')
|
||||
|
|
@ -16,7 +16,8 @@ from tests_python import debugger_unittest
|
|||
from tests_python.debugger_unittest import (CMD_SET_PROPERTY_TRACE, REASON_CAUGHT_EXCEPTION,
|
||||
REASON_UNCAUGHT_EXCEPTION, REASON_STOP_ON_BREAKPOINT, REASON_THREAD_SUSPEND, overrides, CMD_THREAD_CREATE,
|
||||
CMD_GET_THREAD_STACK, REASON_STEP_INTO_MY_CODE, CMD_GET_EXCEPTION_DETAILS, IS_IRONPYTHON, IS_JYTHON, IS_CPYTHON,
|
||||
IS_APPVEYOR, wait_for_condition)
|
||||
IS_APPVEYOR, wait_for_condition, CMD_GET_FRAME, CMD_GET_BREAKPOINT_EXCEPTION,
|
||||
CMD_THREAD_SUSPEND)
|
||||
from _pydevd_bundle.pydevd_constants import IS_WINDOWS
|
||||
try:
|
||||
from urllib import unquote
|
||||
|
|
@ -127,6 +128,89 @@ def test_case_2(case_setup):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'skip_suspend_on_breakpoint_exception, skip_print_breakpoint_exception',
|
||||
(
|
||||
[['NameError'], []],
|
||||
[['NameError'], ['NameError']],
|
||||
[[], []], # Empty means it'll suspend/print in any exception
|
||||
[[], ['NameError']],
|
||||
[['ValueError'], ['Exception']],
|
||||
[['Exception'], ['ValueError']], # ValueError will also suspend/print since we're dealing with a NameError
|
||||
)
|
||||
)
|
||||
def test_case_breakpoint_condition_exc(case_setup, skip_suspend_on_breakpoint_exception, skip_print_breakpoint_exception):
|
||||
|
||||
msgs_in_stderr = (
|
||||
'Error while evaluating expression: i > 5',
|
||||
"NameError: name 'i' is not defined",
|
||||
'Traceback (most recent call last):',
|
||||
'File "<string>", line 1, in <module>',
|
||||
)
|
||||
|
||||
def _ignore_stderr_line(line):
|
||||
if original_ignore_stderr_line(line):
|
||||
return True
|
||||
|
||||
for msg in msgs_in_stderr:
|
||||
if msg in line:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def additional_output_checks(stdout, stderr):
|
||||
original_additional_output_checks(stdout, stderr)
|
||||
if skip_print_breakpoint_exception in ([], ['ValueError']):
|
||||
for msg in msgs_in_stderr:
|
||||
assert msg in stderr
|
||||
else:
|
||||
for msg in msgs_in_stderr:
|
||||
assert msg not in stderr
|
||||
|
||||
with case_setup.test_file('_debugger_case_breakpoint_condition_exc.py') as writer:
|
||||
|
||||
original_ignore_stderr_line = writer._ignore_stderr_line
|
||||
writer._ignore_stderr_line = _ignore_stderr_line
|
||||
|
||||
original_additional_output_checks = writer.additional_output_checks
|
||||
writer.additional_output_checks = additional_output_checks
|
||||
|
||||
writer.write_suspend_on_breakpoint_exception(skip_suspend_on_breakpoint_exception, skip_print_breakpoint_exception)
|
||||
breakpoint_id = writer.write_add_breakpoint(
|
||||
writer.get_line_index_with_content('break here'), 'Call', condition='i > 5')
|
||||
|
||||
writer.write_make_initial_run()
|
||||
|
||||
if skip_suspend_on_breakpoint_exception in ([], ['ValueError']):
|
||||
writer.wait_for_message(lambda msg:msg.startswith('%s\t' % (CMD_GET_BREAKPOINT_EXCEPTION,)))
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
|
||||
if IS_JYTHON:
|
||||
# Jython will break twice.
|
||||
if skip_suspend_on_breakpoint_exception in ([], ['ValueError']):
|
||||
writer.wait_for_message(lambda msg:msg.startswith('%s\t' % (CMD_GET_BREAKPOINT_EXCEPTION,)))
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
thread_id = hit.thread_id
|
||||
frame_id = hit.frame_id
|
||||
|
||||
writer.write_get_frame(thread_id, frame_id)
|
||||
msg = writer.wait_for_message(lambda msg:msg.startswith('%s\t' % (CMD_GET_FRAME,)))
|
||||
name_to_value = {}
|
||||
for var in msg.var:
|
||||
name_to_value[var['name']] = var['value']
|
||||
assert name_to_value == {'i': 'int: 6', 'last_i': 'int: 6'}
|
||||
|
||||
writer.write_remove_breakpoint(breakpoint_id)
|
||||
|
||||
writer.write_run_thread(thread_id)
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_IRONPYTHON, reason='This test fails once in a while due to timing issues on IronPython, so, skipping it.')
|
||||
def test_case_3(case_setup):
|
||||
with case_setup.test_file('_debugger_case3.py') as writer:
|
||||
|
|
@ -2182,7 +2266,7 @@ def test_top_level_exceptions_on_attach(case_setup_remote, check_scenario):
|
|||
|
||||
def check_test_suceeded_msg(writer, stdout, stderr):
|
||||
return 'TEST SUCEEDED' in ''.join(stderr)
|
||||
|
||||
|
||||
def additional_output_checks(writer, stdout, stderr):
|
||||
# Don't call super as we have an expected exception
|
||||
assert 'ValueError: TEST SUCEEDED' in stderr
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue