mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
* Use json for goto and gotoTargets request * Add pydevd tests for goto and gotoTargets * Add id maps to manage goto targets
This commit is contained in:
parent
b65e15a0f3
commit
35be1abb32
4 changed files with 127 additions and 21 deletions
|
|
@ -6,11 +6,12 @@ import os
|
|||
|
||||
from _pydevd_bundle._debug_adapter import pydevd_base_schema
|
||||
from _pydevd_bundle._debug_adapter.pydevd_schema import (SourceBreakpoint, ScopesResponseBody, Scope,
|
||||
VariablesResponseBody, SetVariableResponseBody, ModulesResponseBody, SourceResponseBody)
|
||||
VariablesResponseBody, SetVariableResponseBody, ModulesResponseBody, SourceResponseBody,
|
||||
GotoTargetsResponseBody)
|
||||
from _pydevd_bundle.pydevd_api import PyDevdAPI
|
||||
from _pydevd_bundle.pydevd_comm_constants import (
|
||||
CMD_RETURN, CMD_STEP_OVER_MY_CODE, CMD_STEP_OVER, CMD_STEP_INTO_MY_CODE,
|
||||
CMD_STEP_INTO, CMD_STEP_RETURN_MY_CODE, CMD_STEP_RETURN)
|
||||
CMD_STEP_INTO, CMD_STEP_RETURN_MY_CODE, CMD_STEP_RETURN, CMD_SET_NEXT_STATEMENT)
|
||||
from _pydevd_bundle.pydevd_filtering import ExcludeFilter
|
||||
from _pydevd_bundle.pydevd_json_debug_options import _extract_debug_options
|
||||
from _pydevd_bundle.pydevd_net_command import NetCommand
|
||||
|
|
@ -78,6 +79,25 @@ def _convert_rules_to_exclude_filters(rules, filename_to_server, on_error):
|
|||
return exclude_filters
|
||||
|
||||
|
||||
class IDMap(object):
|
||||
def __init__(self):
|
||||
self._value_to_key = {}
|
||||
self._key_to_value = {}
|
||||
self._next_id = partial(next, itertools.count(0))
|
||||
|
||||
def obtain_value(self, key):
|
||||
return self._key_to_value[key]
|
||||
|
||||
def obtain_key(self, value):
|
||||
try:
|
||||
key = self._value_to_key[value]
|
||||
except KeyError:
|
||||
key = self._next_id()
|
||||
self._key_to_value[key] = value
|
||||
self._value_to_key[value] = key
|
||||
return key
|
||||
|
||||
|
||||
class _PyDevJsonCommandProcessor(object):
|
||||
|
||||
def __init__(self, from_json):
|
||||
|
|
@ -85,6 +105,7 @@ class _PyDevJsonCommandProcessor(object):
|
|||
self.api = PyDevdAPI()
|
||||
self._debug_options = {}
|
||||
self._next_breakpoint_id = partial(next, itertools.count(0))
|
||||
self._goto_targets_map = IDMap()
|
||||
|
||||
def process_net_command_json(self, py_db, json_contents):
|
||||
'''
|
||||
|
|
@ -514,5 +535,36 @@ class _PyDevJsonCommandProcessor(object):
|
|||
response = pydevd_base_schema.build_response(request, kwargs=response_args)
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
def on_gototargets_request(self, py_db, request):
|
||||
path = request.arguments.source.path
|
||||
line = request.arguments.line
|
||||
target_id = self._goto_targets_map.obtain_key((path, line))
|
||||
target = {
|
||||
'id': target_id,
|
||||
'label': '{}:{}'.format(path, line),
|
||||
'line': line
|
||||
}
|
||||
body = GotoTargetsResponseBody(targets=[target])
|
||||
response_args = {'body': body}
|
||||
response = pydevd_base_schema.build_response(request, kwargs=response_args)
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
def on_goto_request(self, py_db, request):
|
||||
target_id = int(request.arguments.targetId)
|
||||
thread_id = request.arguments.threadId
|
||||
try:
|
||||
_, line = self._goto_targets_map.obtain_value(target_id)
|
||||
except KeyError:
|
||||
response = pydevd_base_schema.build_response(request,
|
||||
kwargs={
|
||||
'body': {},
|
||||
'success': False,
|
||||
'message': 'Unknown goto target id: %d' % (target_id,),
|
||||
})
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
self.api.request_set_next(py_db, thread_id, CMD_SET_NEXT_STATEMENT, line, '*')
|
||||
response = pydevd_base_schema.build_response(request, kwargs={'body': {}})
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
process_net_command_json = _PyDevJsonCommandProcessor(pydevd_base_schema.from_json).process_net_command_json
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
def method():
|
||||
a = 1
|
||||
a = 1 # Step here
|
||||
print('call %s' % (a,))
|
||||
a = 2
|
||||
print('call %s' % (a,))
|
||||
a = 3
|
||||
a = 3 # Break here
|
||||
|
||||
if __name__ == '__main__':
|
||||
method()
|
||||
|
|
|
|||
|
|
@ -1021,6 +1021,63 @@ def test_exception_details(case_setup):
|
|||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
def test_goto(case_setup):
|
||||
with case_setup.test_file('_debugger_case_set_next_statement.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
break_line = writer.get_line_index_with_content('Break here')
|
||||
step_line = writer.get_line_index_with_content('Step here')
|
||||
writer.write_add_breakpoint(break_line)
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
|
||||
stack_trace_request = json_facade.write_request(
|
||||
pydevd_schema.StackTraceRequest(pydevd_schema.StackTraceArguments(threadId=hit.thread_id)))
|
||||
stack_trace_response = json_facade.wait_for_response(stack_trace_request)
|
||||
stack_frame = next(iter(stack_trace_response.body.stackFrames))
|
||||
assert stack_frame['line'] == break_line
|
||||
|
||||
goto_targets_request = json_facade.write_request(
|
||||
pydevd_schema.GotoTargetsRequest(pydevd_schema.GotoTargetsArguments(
|
||||
source=pydevd_schema.Source(path=writer.TEST_FILE, sourceReference=0),
|
||||
line=step_line)))
|
||||
goto_targets_response = json_facade.wait_for_response(goto_targets_request)
|
||||
target_id = goto_targets_response.body.targets[0]['id']
|
||||
|
||||
goto_request = json_facade.write_request(
|
||||
pydevd_schema.GotoRequest(pydevd_schema.GotoArguments(
|
||||
threadId=hit.thread_id,
|
||||
targetId=12345)))
|
||||
goto_response = json_facade.wait_for_response(goto_request)
|
||||
assert not goto_response.success
|
||||
|
||||
goto_request = json_facade.write_request(
|
||||
pydevd_schema.GotoRequest(pydevd_schema.GotoArguments(
|
||||
threadId=hit.thread_id,
|
||||
targetId=target_id)))
|
||||
goto_response = json_facade.wait_for_response(goto_request)
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit(reason='127')
|
||||
|
||||
stack_trace_request = json_facade.write_request(
|
||||
pydevd_schema.StackTraceRequest(pydevd_schema.StackTraceArguments(threadId=hit.thread_id)))
|
||||
stack_trace_response = json_facade.wait_for_response(stack_trace_request)
|
||||
stack_frame = next(iter(stack_trace_response.body.stackFrames))
|
||||
assert stack_frame['line'] == step_line
|
||||
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
|
||||
# we hit the breakpoint again. Since we moved back
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='Flaky on Jython.')
|
||||
def test_path_translation_and_source_reference(case_setup):
|
||||
|
||||
|
|
|
|||
|
|
@ -1237,7 +1237,6 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
|
|||
self.new_thread_lock = threading.Lock()
|
||||
|
||||
# goto
|
||||
self.goto_target_map = IDMap()
|
||||
self.current_goto_request = None
|
||||
|
||||
# adapter state
|
||||
|
|
@ -1761,14 +1760,12 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
|
|||
|
||||
@async_handler
|
||||
def on_gotoTargets(self, request, args):
|
||||
path = args['source']['path']
|
||||
line = args['line']
|
||||
target_id = self.goto_target_map.to_vscode((path, line), autogen=True)
|
||||
self.send_response(request, targets=[{
|
||||
'id': target_id,
|
||||
'label': '{}:{}'.format(path, line),
|
||||
'line': line,
|
||||
}])
|
||||
pydevd_request = copy.deepcopy(request)
|
||||
del pydevd_request['seq'] # A new seq should be created for pydevd.
|
||||
cmd_id = pydevd_comm.CMD_GET_NEXT_STATEMENT_TARGETS
|
||||
_, _, resp_args = yield self.pydevd_request(cmd_id, pydevd_request, is_json=True)
|
||||
|
||||
self.send_response(request, targets=resp_args['body']['targets'])
|
||||
|
||||
@async_handler
|
||||
def on_goto(self, request, args):
|
||||
|
|
@ -1776,16 +1773,16 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
|
|||
self.send_error_response(request, 'Already processing a "goto" request.')
|
||||
return
|
||||
|
||||
vsc_tid = args['threadId']
|
||||
target_id = args['targetId']
|
||||
|
||||
pyd_tid = self.thread_map.to_pydevd(vsc_tid)
|
||||
path, line = self.goto_target_map.to_pydevd(target_id)
|
||||
pyd_tid = self.thread_map.to_pydevd(int(args['threadId']))
|
||||
pydevd_request = copy.deepcopy(request)
|
||||
del pydevd_request['seq'] # A new seq should be created for pydevd.
|
||||
pydevd_request['arguments']['threadId'] = pyd_tid
|
||||
|
||||
self.current_goto_request = request
|
||||
self.pydevd_notify(
|
||||
pydevd_comm.CMD_SET_NEXT_STATEMENT,
|
||||
'{}\t{}\t*'.format(pyd_tid, line))
|
||||
cmd_id = pydevd_comm.CMD_SET_NEXT_STATEMENT
|
||||
yield self.pydevd_request(cmd_id, pydevd_request, is_json=True)
|
||||
# response for this is received via set_next_statement event
|
||||
# see on_pydevd_set_next_statement below
|
||||
|
||||
@async_handler
|
||||
def on_setBreakpoints(self, request, args):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue