mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Support function breakpoints. Fixes #468
This commit is contained in:
parent
623c503b58
commit
d7970b80ad
12 changed files with 4602 additions and 3998 deletions
|
|
@ -657,6 +657,14 @@ class PyDevdAPI(object):
|
|||
|
||||
py_db.on_breakpoints_changed(removed=True)
|
||||
|
||||
def set_function_breakpoints(self, py_db, function_breakpoints):
|
||||
function_breakpoint_name_to_breakpoint = {}
|
||||
for function_breakpoint in function_breakpoints:
|
||||
function_breakpoint_name_to_breakpoint[function_breakpoint.func_name] = function_breakpoint
|
||||
|
||||
py_db.function_breakpoint_name_to_breakpoint = function_breakpoint_name_to_breakpoint
|
||||
py_db.on_breakpoints_changed()
|
||||
|
||||
def request_exec_or_evaluate(
|
||||
self, py_db, seq, thread_id, frame_id, expression, is_exec, trim_if_too_big, attr_to_set_result):
|
||||
py_db.post_method_as_internal_command(
|
||||
|
|
|
|||
|
|
@ -77,6 +77,36 @@ class LineBreakpoint(object):
|
|||
return ret
|
||||
|
||||
|
||||
class FunctionBreakpoint(object):
|
||||
|
||||
def __init__(self, func_name, condition, expression, suspend_policy="NONE", hit_condition=None, is_logpoint=False):
|
||||
self.condition = condition
|
||||
self.func_name = func_name
|
||||
self.expression = expression
|
||||
self.suspend_policy = suspend_policy
|
||||
self.hit_condition = hit_condition
|
||||
self._hit_count = 0
|
||||
self._hit_condition_lock = threading.Lock()
|
||||
self.is_logpoint = is_logpoint
|
||||
|
||||
@property
|
||||
def has_condition(self):
|
||||
return bool(self.condition) or bool(self.hit_condition)
|
||||
|
||||
def handle_hit_condition(self, frame):
|
||||
if not self.hit_condition:
|
||||
return False
|
||||
ret = False
|
||||
with self._hit_condition_lock:
|
||||
self._hit_count += 1
|
||||
expr = self.hit_condition.replace('@HIT@', str(self._hit_count))
|
||||
try:
|
||||
ret = bool(eval(expr, frame.f_globals, frame.f_locals))
|
||||
except Exception:
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
|
||||
def get_exception_breakpoint(exctype, exceptions):
|
||||
if not exctype:
|
||||
exception_full_qname = None
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ CMD_STEP_INTO_COROUTINE = 206
|
|||
|
||||
CMD_LOAD_SOURCE_FROM_FRAME_ID = 207
|
||||
|
||||
CMD_SET_FUNCTION_BREAK = 208
|
||||
|
||||
CMD_VERSION = 501
|
||||
CMD_RETURN = 502
|
||||
CMD_SET_PROTOCOL = 503
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -154,7 +154,7 @@ from _pydevd_bundle.pydevd_constants import (dict_iter_values, IS_PY3K, RETURN_V
|
|||
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, just_raised, remove_exception_from_frame, ignore_exception_trace
|
||||
from _pydevd_bundle.pydevd_utils import get_clsname_for_code
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame
|
||||
from _pydevd_bundle.pydevd_comm_constants import constant_to_str
|
||||
from _pydevd_bundle.pydevd_comm_constants import constant_to_str, CMD_SET_FUNCTION_BREAK
|
||||
try:
|
||||
from _pydevd_bundle.pydevd_bytecode_utils import get_smart_step_into_variant_from_frame_offset
|
||||
except ImportError:
|
||||
|
|
@ -718,6 +718,7 @@ cdef class PyDBFrame:
|
|||
|
||||
stop_frame = info.pydev_step_stop
|
||||
step_cmd = info.pydev_step_cmd
|
||||
function_breakpoint_on_call_event = None
|
||||
|
||||
if frame.f_code.co_flags & 0xa0: # 0xa0 == CO_GENERATOR = 0x20 | CO_COROUTINE = 0x80
|
||||
# Dealing with coroutines and generators:
|
||||
|
|
@ -840,6 +841,8 @@ cdef class PyDBFrame:
|
|||
is_call = True
|
||||
is_return = False
|
||||
is_exception_event = False
|
||||
if frame.f_code.co_firstlineno == frame.f_lineno: # Check line to deal with async/await.
|
||||
function_breakpoint_on_call_event = main_debugger.function_breakpoint_name_to_breakpoint.get(frame.f_code.co_name)
|
||||
|
||||
elif event == 'exception':
|
||||
is_exception_event = True
|
||||
|
|
@ -909,7 +912,11 @@ cdef class PyDBFrame:
|
|||
# we will return nothing for the next trace
|
||||
# also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway,
|
||||
# so, that's why the additional checks are there.
|
||||
if not breakpoints_for_file:
|
||||
|
||||
if function_breakpoint_on_call_event:
|
||||
pass # Do nothing here (just keep on going as we can't skip it).
|
||||
|
||||
elif not breakpoints_for_file:
|
||||
if can_skip:
|
||||
if has_exception_breakpoints:
|
||||
return self.trace_exception
|
||||
|
|
@ -983,8 +990,16 @@ cdef class PyDBFrame:
|
|||
breakpoint = None
|
||||
exist_result = False
|
||||
stop = False
|
||||
stop_reason = 111
|
||||
bp_type = None
|
||||
if not is_return and info.pydev_state != 2 and breakpoints_for_file is not None and line in breakpoints_for_file:
|
||||
|
||||
if function_breakpoint_on_call_event:
|
||||
breakpoint = function_breakpoint_on_call_event
|
||||
stop = True
|
||||
new_frame = frame
|
||||
stop_reason = CMD_SET_FUNCTION_BREAK
|
||||
|
||||
elif not is_return and info.pydev_state != 2 and breakpoints_for_file is not None and line in breakpoints_for_file:
|
||||
breakpoint = breakpoints_for_file[line]
|
||||
new_frame = frame
|
||||
stop = True
|
||||
|
|
@ -1049,7 +1064,7 @@ cdef class PyDBFrame:
|
|||
if stop:
|
||||
self.set_suspend(
|
||||
thread,
|
||||
111,
|
||||
stop_reason,
|
||||
suspend_other_threads=breakpoint and breakpoint.suspend_policy == "ALL",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from _pydevd_bundle.pydevd_constants import (dict_iter_values, IS_PY3K, RETURN_V
|
|||
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, just_raised, remove_exception_from_frame, ignore_exception_trace
|
||||
from _pydevd_bundle.pydevd_utils import get_clsname_for_code
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame
|
||||
from _pydevd_bundle.pydevd_comm_constants import constant_to_str
|
||||
from _pydevd_bundle.pydevd_comm_constants import constant_to_str, CMD_SET_FUNCTION_BREAK
|
||||
try:
|
||||
from _pydevd_bundle.pydevd_bytecode_utils import get_smart_step_into_variant_from_frame_offset
|
||||
except ImportError:
|
||||
|
|
@ -585,6 +585,7 @@ class PyDBFrame:
|
|||
|
||||
stop_frame = info.pydev_step_stop
|
||||
step_cmd = info.pydev_step_cmd
|
||||
function_breakpoint_on_call_event = None
|
||||
|
||||
if frame.f_code.co_flags & 0xa0: # 0xa0 == CO_GENERATOR = 0x20 | CO_COROUTINE = 0x80
|
||||
# Dealing with coroutines and generators:
|
||||
|
|
@ -707,6 +708,8 @@ class PyDBFrame:
|
|||
is_call = True
|
||||
is_return = False
|
||||
is_exception_event = False
|
||||
if frame.f_code.co_firstlineno == frame.f_lineno: # Check line to deal with async/await.
|
||||
function_breakpoint_on_call_event = main_debugger.function_breakpoint_name_to_breakpoint.get(frame.f_code.co_name)
|
||||
|
||||
elif event == 'exception':
|
||||
is_exception_event = True
|
||||
|
|
@ -776,7 +779,11 @@ class PyDBFrame:
|
|||
# we will return nothing for the next trace
|
||||
# also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway,
|
||||
# so, that's why the additional checks are there.
|
||||
if not breakpoints_for_file:
|
||||
|
||||
if function_breakpoint_on_call_event:
|
||||
pass # Do nothing here (just keep on going as we can't skip it).
|
||||
|
||||
elif not breakpoints_for_file:
|
||||
if can_skip:
|
||||
if has_exception_breakpoints:
|
||||
return self.trace_exception
|
||||
|
|
@ -850,8 +857,16 @@ class PyDBFrame:
|
|||
breakpoint = None
|
||||
exist_result = False
|
||||
stop = False
|
||||
stop_reason = CMD_SET_BREAK
|
||||
bp_type = None
|
||||
if not is_return and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None and line in breakpoints_for_file:
|
||||
|
||||
if function_breakpoint_on_call_event:
|
||||
breakpoint = function_breakpoint_on_call_event
|
||||
stop = True
|
||||
new_frame = frame
|
||||
stop_reason = CMD_SET_FUNCTION_BREAK
|
||||
|
||||
elif not is_return and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None and line in breakpoints_for_file:
|
||||
breakpoint = breakpoints_for_file[line]
|
||||
new_frame = frame
|
||||
stop = True
|
||||
|
|
@ -916,7 +931,7 @@ class PyDBFrame:
|
|||
if stop:
|
||||
self.set_suspend(
|
||||
thread,
|
||||
CMD_SET_BREAK,
|
||||
stop_reason,
|
||||
suspend_other_threads=breakpoint and breakpoint.suspend_policy == "ALL",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ from _pydevd_bundle.pydevd_comm_constants import CMD_THREAD_CREATE, CMD_RETURN,
|
|||
CMD_STEP_RETURN, CMD_STEP_CAUGHT_EXCEPTION, CMD_ADD_EXCEPTION_BREAK, CMD_SET_BREAK, \
|
||||
CMD_SET_NEXT_STATEMENT, CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION, \
|
||||
CMD_THREAD_RESUME_SINGLE_NOTIFICATION, CMD_THREAD_KILL, CMD_STOP_ON_START, CMD_INPUT_REQUESTED, \
|
||||
CMD_EXIT, CMD_STEP_INTO_COROUTINE, CMD_STEP_RETURN_MY_CODE, CMD_SMART_STEP_INTO
|
||||
CMD_EXIT, CMD_STEP_INTO_COROUTINE, CMD_STEP_RETURN_MY_CODE, CMD_SMART_STEP_INTO, \
|
||||
CMD_SET_FUNCTION_BREAK
|
||||
from _pydevd_bundle.pydevd_constants import get_thread_id, dict_values, ForkSafeLock
|
||||
from _pydevd_bundle.pydevd_net_command import NetCommand, NULL_NET_COMMAND
|
||||
from _pydevd_bundle.pydevd_net_command_factory_xml import NetCommandFactory
|
||||
|
|
@ -327,6 +328,8 @@ class NetCommandFactoryJson(NetCommandFactory):
|
|||
stop_reason = 'exception'
|
||||
elif stop_reason == CMD_SET_BREAK:
|
||||
stop_reason = 'breakpoint'
|
||||
elif stop_reason == CMD_SET_FUNCTION_BREAK:
|
||||
stop_reason = 'function breakpoint'
|
||||
elif stop_reason == CMD_SET_NEXT_STATEMENT:
|
||||
stop_reason = 'goto'
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ from _pydevd_bundle._debug_adapter.pydevd_schema import (
|
|||
SetVariableResponseBody, SourceBreakpoint, SourceResponseBody,
|
||||
VariablesResponseBody, SetBreakpointsResponseBody, Response,
|
||||
Capabilities, PydevdAuthorizeRequest, Request, StepInTargetsResponse, StepInTarget,
|
||||
StepInTargetsResponseBody)
|
||||
StepInTargetsResponseBody, SetFunctionBreakpointsResponseBody)
|
||||
from _pydevd_bundle.pydevd_api import PyDevdAPI
|
||||
from _pydevd_bundle.pydevd_breakpoints import get_exception_class
|
||||
from _pydevd_bundle.pydevd_breakpoints import get_exception_class, FunctionBreakpoint
|
||||
from _pydevd_bundle.pydevd_comm_constants import (
|
||||
CMD_PROCESS_EVENT, CMD_RETURN, CMD_SET_NEXT_STATEMENT, CMD_STEP_INTO,
|
||||
CMD_STEP_INTO_MY_CODE, CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE, file_system_encoding,
|
||||
|
|
@ -223,6 +223,7 @@ class PyDevJsonCommandProcessor(object):
|
|||
supportsSetExpression=True,
|
||||
supportsTerminateRequest=True,
|
||||
supportsClipboardContext=True,
|
||||
supportsFunctionBreakpoints=True,
|
||||
|
||||
exceptionBreakpointFilters=[
|
||||
{'filter': 'raised', 'label': 'Raised Exceptions', 'default': False},
|
||||
|
|
@ -231,7 +232,6 @@ class PyDevJsonCommandProcessor(object):
|
|||
],
|
||||
|
||||
# Not supported.
|
||||
supportsFunctionBreakpoints=False,
|
||||
supportsStepBack=False,
|
||||
supportsRestartFrame=False,
|
||||
supportsStepInTargetsRequest=True,
|
||||
|
|
@ -445,7 +445,7 @@ class PyDevJsonCommandProcessor(object):
|
|||
if IS_PY2 and isinstance(w, unicode):
|
||||
w = w.encode(getfilesystemencoding())
|
||||
|
||||
new_watch_dirs.add(pydevd_file_utils.get_path_with_real_case(pydevd_file_utils.absolute_path(w)))
|
||||
new_watch_dirs.add(pydevd_file_utils.get_path_with_real_case(pydevd_file_utils.absolute_path(w)))
|
||||
except Exception:
|
||||
pydev_log.exception('Error adding watch dir: %s', w)
|
||||
watch_dirs = new_watch_dirs
|
||||
|
|
@ -681,14 +681,14 @@ class PyDevJsonCommandProcessor(object):
|
|||
response = pydevd_base_schema.build_response(request)
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
def on_setbreakpoints_request(self, py_db, request):
|
||||
'''
|
||||
:param SetBreakpointsRequest request:
|
||||
'''
|
||||
def _verify_launch_or_attach_done(self, request):
|
||||
if not self._launch_or_attach_request_done:
|
||||
# Note that to validate the breakpoints we need the launch request to be done already
|
||||
# (otherwise the filters wouldn't be set for the breakpoint validation).
|
||||
body = SetBreakpointsResponseBody([])
|
||||
if request.command == 'setFunctionBreakpoints':
|
||||
body = SetFunctionBreakpointsResponseBody([])
|
||||
else:
|
||||
body = SetBreakpointsResponseBody([])
|
||||
response = pydevd_base_schema.build_response(
|
||||
request,
|
||||
kwargs={
|
||||
|
|
@ -698,6 +698,48 @@ class PyDevJsonCommandProcessor(object):
|
|||
})
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
def on_setfunctionbreakpoints_request(self, py_db, request):
|
||||
'''
|
||||
:param SetFunctionBreakpointsRequest request:
|
||||
'''
|
||||
response = self._verify_launch_or_attach_done(request)
|
||||
if response is not None:
|
||||
return response
|
||||
|
||||
arguments = request.arguments # : :type arguments: SetFunctionBreakpointsArguments
|
||||
function_breakpoints = []
|
||||
suspend_policy = 'ALL'
|
||||
|
||||
# Not currently covered by the DAP.
|
||||
is_logpoint = False
|
||||
expression = None
|
||||
|
||||
breakpoints_set = []
|
||||
for bp in arguments.breakpoints:
|
||||
hit_condition = self._get_hit_condition_expression(bp.get('hitCondition'))
|
||||
condition = bp.get('condition')
|
||||
|
||||
function_breakpoints.append(
|
||||
FunctionBreakpoint(bp['name'], condition, expression, suspend_policy, hit_condition, is_logpoint))
|
||||
|
||||
# Note: always succeeds.
|
||||
breakpoints_set.append(pydevd_schema.Breakpoint(
|
||||
verified=True, id=self._next_breakpoint_id()).to_dict())
|
||||
|
||||
self.api.set_function_breakpoints(py_db, function_breakpoints)
|
||||
|
||||
body = {'breakpoints': breakpoints_set}
|
||||
set_breakpoints_response = pydevd_base_schema.build_response(request, kwargs={'body': body})
|
||||
return NetCommand(CMD_RETURN, 0, set_breakpoints_response, is_json=True)
|
||||
|
||||
def on_setbreakpoints_request(self, py_db, request):
|
||||
'''
|
||||
:param SetBreakpointsRequest request:
|
||||
'''
|
||||
response = self._verify_launch_or_attach_done(request)
|
||||
if response is not None:
|
||||
return response
|
||||
|
||||
arguments = request.arguments # : :type arguments: SetBreakpointsArguments
|
||||
# TODO: Path is optional here it could be source reference.
|
||||
filename = self.api.filename_to_str(arguments.source.path)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -125,6 +125,7 @@ cdef class ThreadInfo:
|
|||
cdef class FuncCodeInfo:
|
||||
|
||||
cdef public str co_filename
|
||||
cdef public str co_name
|
||||
cdef public str canonical_normalized_filename
|
||||
cdef bint always_skip_code
|
||||
cdef public bint breakpoint_found
|
||||
|
|
@ -240,6 +241,7 @@ cdef FuncCodeInfo get_func_code_info(ThreadInfo thread_info, PyFrameObject * fra
|
|||
return func_code_info_obj
|
||||
|
||||
cdef str co_filename = <str> code_obj.co_filename
|
||||
cdef str co_name = <str> code_obj.co_name
|
||||
cdef dict cache_file_type
|
||||
cdef tuple cache_file_type_key
|
||||
|
||||
|
|
@ -247,6 +249,7 @@ cdef FuncCodeInfo get_func_code_info(ThreadInfo thread_info, PyFrameObject * fra
|
|||
func_code_info.breakpoints_mtime = main_debugger.mtime
|
||||
|
||||
func_code_info.co_filename = co_filename
|
||||
func_code_info.co_name = co_name
|
||||
|
||||
if not func_code_info.always_skip_code:
|
||||
try:
|
||||
|
|
@ -272,6 +275,7 @@ cdef FuncCodeInfo get_func_code_info(ThreadInfo thread_info, PyFrameObject * fra
|
|||
if main_debugger is not None:
|
||||
|
||||
breakpoints: dict = main_debugger.breakpoints.get(func_code_info.canonical_normalized_filename)
|
||||
function_breakpoint: object = main_debugger.function_breakpoint_name_to_breakpoint.get(func_code_info.co_name)
|
||||
# print('\n---')
|
||||
# print(main_debugger.breakpoints)
|
||||
# print(func_code_info.canonical_normalized_filename)
|
||||
|
|
@ -289,6 +293,11 @@ cdef FuncCodeInfo get_func_code_info(ThreadInfo thread_info, PyFrameObject * fra
|
|||
cached_code_obj_info.compute_force_stay_in_untraced_mode(breakpoints)
|
||||
func_code_info.breakpoint_found = breakpoint_found
|
||||
|
||||
elif function_breakpoint:
|
||||
# Go directly into tracing mode
|
||||
func_code_info.breakpoint_found = True
|
||||
func_code_info.new_code = None
|
||||
|
||||
elif breakpoints:
|
||||
# if DEBUG:
|
||||
# print('found breakpoints', code_obj_py.co_name, breakpoints)
|
||||
|
|
|
|||
|
|
@ -530,6 +530,7 @@ class PyDB(object):
|
|||
|
||||
# These are the breakpoints meant to be consumed during runtime.
|
||||
self.breakpoints = {}
|
||||
self.function_breakpoint_name_to_breakpoint = {}
|
||||
|
||||
# Set communication protocol
|
||||
PyDevdAPI().set_protocol(self, 0, PydevdCustomization.DEFAULT_PROTOCOL)
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@ from _pydevd_bundle._debug_adapter import pydevd_schema, pydevd_base_schema
|
|||
from _pydevd_bundle._debug_adapter.pydevd_base_schema import from_json
|
||||
from _pydevd_bundle._debug_adapter.pydevd_schema import (ThreadEvent, ModuleEvent, OutputEvent,
|
||||
ExceptionOptions, Response, StoppedEvent, ContinuedEvent, ProcessEvent, InitializeRequest,
|
||||
InitializeRequestArguments, TerminateArguments, TerminateRequest, TerminatedEvent)
|
||||
InitializeRequestArguments, TerminateArguments, TerminateRequest, TerminatedEvent,
|
||||
FunctionBreakpoint, SetFunctionBreakpointsRequest, SetFunctionBreakpointsArguments)
|
||||
from _pydevd_bundle.pydevd_comm_constants import file_system_encoding
|
||||
from _pydevd_bundle.pydevd_constants import (int_types, IS_64BIT_PROCESS,
|
||||
PY_VERSION_STR, PY_IMPL_VERSION_STR, PY_IMPL_NAME, IS_PY36_OR_GREATER,
|
||||
IS_PYPY, GENERATED_LEN_ATTR_NAME, IS_WINDOWS, IS_LINUX, IS_MAC)
|
||||
from tests_python import debugger_unittest
|
||||
from tests_python.debug_constants import TEST_CHERRYPY, IS_PY2, TEST_DJANGO, TEST_FLASK, IS_PY26, \
|
||||
IS_PY27, IS_CPYTHON, TEST_GEVENT, TEST_CYTHON, IS_PY36_OR_GREATER
|
||||
IS_PY27, IS_CPYTHON, TEST_GEVENT, TEST_CYTHON
|
||||
from tests_python.debugger_unittest import (IS_JYTHON, IS_APPVEYOR, overrides,
|
||||
get_free_port, wait_for_condition)
|
||||
from _pydevd_bundle.pydevd_utils import DAPGrouper
|
||||
|
|
@ -154,6 +155,14 @@ class JsonFacade(object):
|
|||
assert found_line in line, 'Expect to break at line: %s. Found: %s (file: %s)' % (line, found_line, path)
|
||||
return json_hit
|
||||
|
||||
def write_set_function_breakpoints(
|
||||
self, function_names):
|
||||
function_breakpoints = [FunctionBreakpoint(name,) for name in function_names]
|
||||
arguments = SetFunctionBreakpointsArguments(function_breakpoints)
|
||||
request = SetFunctionBreakpointsRequest(arguments)
|
||||
response = self.wait_for_response(self.write_request(request))
|
||||
assert response.success
|
||||
|
||||
def write_set_breakpoints(
|
||||
self,
|
||||
lines,
|
||||
|
|
@ -5545,6 +5554,46 @@ def test_step_into_target_genexpr(case_setup):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
def test_function_breakpoints_basic(case_setup, pyfile):
|
||||
|
||||
@pyfile
|
||||
def module():
|
||||
|
||||
def do_something(): # break here
|
||||
print('TEST SUCEEDED')
|
||||
|
||||
if __name__ == '__main__':
|
||||
do_something()
|
||||
|
||||
with case_setup.test_file(module) as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
json_facade.write_launch(justMyCode=False)
|
||||
bp = writer.get_line_index_with_content('break here')
|
||||
json_facade.write_set_function_breakpoints(['do_something'])
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = json_facade.wait_for_thread_stopped('function breakpoint', line=bp)
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(not IS_PY36_OR_GREATER, reason='Python 3.6 onwards required for test.')
|
||||
def test_function_breakpoints_async(case_setup):
|
||||
|
||||
with case_setup.test_file('_debugger_case_stop_async_iteration.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
json_facade.write_launch(justMyCode=False)
|
||||
bp = writer.get_line_index_with_content('async def gen():')
|
||||
json_facade.write_set_function_breakpoints(['gen'])
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = json_facade.wait_for_thread_stopped('function breakpoint', line=bp)
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['-k', 'test_case_skipping_filters', '-s'])
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue