mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Properly translate line in Goto Target. Fixes #150
This commit is contained in:
parent
aa36155221
commit
44a07d030e
5 changed files with 108 additions and 5 deletions
|
|
@ -228,9 +228,31 @@ class PyDevdAPI(object):
|
|||
elif thread_id.startswith('__frame__:'):
|
||||
sys.stderr.write("Can't make tasklet step command: %s\n" % (thread_id,))
|
||||
|
||||
def request_set_next(self, py_db, seq, thread_id, set_next_cmd_id, line, func_name):
|
||||
def request_set_next(self, py_db, seq, thread_id, set_next_cmd_id, original_filename, line, func_name):
|
||||
'''
|
||||
:param Optional[str] original_filename:
|
||||
If available, the filename may be source translated, otherwise no translation will take
|
||||
place (the set next just needs the line afterwards as it executes locally, but for
|
||||
the Jupyter integration, the source mapping may change the actual lines and not only
|
||||
the filename).
|
||||
'''
|
||||
t = pydevd_find_thread_by_id(thread_id)
|
||||
if t:
|
||||
if original_filename is not None:
|
||||
translated_filename = self.filename_to_server(original_filename) # Apply user path mapping.
|
||||
pydev_log.debug('Set next (after path translation) in: %s line: %s', translated_filename, line)
|
||||
func_name = self.to_str(func_name)
|
||||
|
||||
assert translated_filename.__class__ == str # i.e.: bytes on py2 and str on py3
|
||||
assert func_name.__class__ == str # i.e.: bytes on py2 and str on py3
|
||||
|
||||
# Apply source mapping (i.e.: ipython).
|
||||
_source_mapped_filename, new_line, multi_mapping_applied = py_db.source_mapping.map_to_server(
|
||||
translated_filename, line)
|
||||
if multi_mapping_applied:
|
||||
pydev_log.debug('Set next (after source mapping) in: %s line: %s', translated_filename, line)
|
||||
line = new_line
|
||||
|
||||
int_cmd = InternalSetNextStatementThread(thread_id, set_next_cmd_id, line, func_name, seq=seq)
|
||||
py_db.post_internal_command(int_cmd, thread_id)
|
||||
elif thread_id.startswith('__frame__:'):
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ class _PyDevCommandProcessor(object):
|
|||
|
||||
def _cmd_set_next(self, py_db, cmd_id, seq, text):
|
||||
thread_id, line, func_name = text.split('\t', 2)
|
||||
return self.api.request_set_next(py_db, seq, thread_id, cmd_id, line, func_name)
|
||||
return self.api.request_set_next(py_db, seq, thread_id, cmd_id, None, line, func_name)
|
||||
|
||||
cmd_run_to_line = _cmd_set_next
|
||||
cmd_set_next_statement = _cmd_set_next
|
||||
|
|
@ -366,7 +366,6 @@ class _PyDevCommandProcessor(object):
|
|||
if debug or force:
|
||||
pydevd_file_utils.DEBUG_CLIENT_SERVER_TRANSLATION = debug
|
||||
|
||||
|
||||
def cmd_set_py_exception_json(self, py_db, cmd_id, seq, text):
|
||||
# This API is optional and works 'in bulk' -- it's possible
|
||||
# to get finer-grained control with CMD_ADD_EXCEPTION_BREAK/CMD_REMOVE_EXCEPTION_BREAK
|
||||
|
|
|
|||
|
|
@ -994,7 +994,7 @@ class PyDevJsonCommandProcessor(object):
|
|||
target_id = int(request.arguments.targetId)
|
||||
thread_id = request.arguments.threadId
|
||||
try:
|
||||
_, line = self._goto_targets_map.obtain_value(target_id)
|
||||
path, line = self._goto_targets_map.obtain_value(target_id)
|
||||
except KeyError:
|
||||
response = pydevd_base_schema.build_response(
|
||||
request,
|
||||
|
|
@ -1005,7 +1005,7 @@ class PyDevJsonCommandProcessor(object):
|
|||
})
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
self.api.request_set_next(py_db, request.seq, thread_id, CMD_SET_NEXT_STATEMENT, line, '*')
|
||||
self.api.request_set_next(py_db, request.seq, thread_id, CMD_SET_NEXT_STATEMENT, path, line, '*')
|
||||
# See 'NetCommandFactoryJson.make_set_next_stmnt_status_message' for response
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# Some comment lines to move the function below
|
||||
# Some comment lines to move the function below
|
||||
# Some comment lines to move the function below
|
||||
# Some comment lines to move the function below
|
||||
|
||||
|
||||
def full_function():
|
||||
# Note that this function is not called, it's there just to make the mapping explicit.
|
||||
# The test case should stop at `a = 1` and then skip the `print('Skip this print')`.
|
||||
# map to Cell1, line 1
|
||||
a = 1 # map to Cell1, line 2
|
||||
print('Skip this print') # map to Cell1, line 3
|
||||
print('TEST SUCEEDED') # map to Cell1, line 4
|
||||
b = 2 # map to Cell1, line 5
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
code = compile('''# line 1
|
||||
a = 1 # line 2
|
||||
print('Skip this print') # line 3
|
||||
print('TEST SUCEEDED') # line 4
|
||||
b = 2 # line 5
|
||||
''', '<Cell1>', 'exec')
|
||||
exec(code)
|
||||
|
|
@ -3293,6 +3293,64 @@ def test_source_mapping_just_my_code(case_setup):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
def test_source_mapping_goto_target(case_setup):
|
||||
from _pydevd_bundle._debug_adapter.pydevd_schema import Source
|
||||
from _pydevd_bundle._debug_adapter.pydevd_schema import PydevdSourceMap
|
||||
|
||||
def additional_output_checks(writer, stdout, stderr):
|
||||
assert 'Skip this print' not in stdout
|
||||
assert 'TEST SUCEEDED' in stdout
|
||||
|
||||
with case_setup.test_file('_debugger_case_source_map_goto_target.py', additional_output_checks=additional_output_checks) as writer:
|
||||
test_file = writer.TEST_FILE
|
||||
if isinstance(test_file, bytes):
|
||||
# file is in the filesystem encoding (needed for launch) but protocol needs it in utf-8
|
||||
test_file = test_file.decode(file_system_encoding)
|
||||
test_file = test_file.encode('utf-8')
|
||||
|
||||
json_facade = JsonFacade(writer)
|
||||
json_facade.write_launch(justMyCode=False)
|
||||
|
||||
map_to_cell_1_line1 = writer.get_line_index_with_content('map to Cell1, line 1')
|
||||
map_to_cell_1_line2 = writer.get_line_index_with_content('map to Cell1, line 2')
|
||||
map_to_cell_1_line4 = writer.get_line_index_with_content('map to Cell1, line 4')
|
||||
map_to_cell_1_line5 = writer.get_line_index_with_content('map to Cell1, line 5')
|
||||
|
||||
cell1_map = PydevdSourceMap(map_to_cell_1_line1, map_to_cell_1_line5, Source(path='<Cell1>'), 1)
|
||||
pydevd_source_maps = [cell1_map]
|
||||
json_facade.write_set_pydevd_source_map(
|
||||
Source(path=test_file),
|
||||
pydevd_source_maps=pydevd_source_maps,
|
||||
)
|
||||
json_facade.write_set_breakpoints(map_to_cell_1_line2)
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
json_hit = json_facade.wait_for_thread_stopped(line=map_to_cell_1_line2, file=os.path.basename(test_file))
|
||||
for stack_frame in json_hit.stack_trace_response.body.stackFrames:
|
||||
assert stack_frame['source']['sourceReference'] == 0
|
||||
|
||||
goto_targets_request = json_facade.write_request(
|
||||
pydevd_schema.GotoTargetsRequest(pydevd_schema.GotoTargetsArguments(
|
||||
source=pydevd_schema.Source(path=writer.TEST_FILE, sourceReference=0),
|
||||
line=map_to_cell_1_line4)))
|
||||
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=json_hit.thread_id,
|
||||
targetId=target_id)))
|
||||
goto_response = json_facade.wait_for_response(goto_request)
|
||||
assert goto_response.success
|
||||
|
||||
json_hit = json_facade.wait_for_thread_stopped('goto')
|
||||
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(not TEST_CHERRYPY or IS_WINDOWS, reason='No CherryPy available / not ok in Windows.')
|
||||
def test_process_autoreload_cherrypy(case_setup_multiprocessing, tmpdir):
|
||||
'''
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue