diff --git a/_pydevd_bundle/pydevd_constants.py b/_pydevd_bundle/pydevd_constants.py index 01d1951f..419938a5 100644 --- a/_pydevd_bundle/pydevd_constants.py +++ b/_pydevd_bundle/pydevd_constants.py @@ -346,6 +346,9 @@ def as_int_in_env(env_key, default): # If PYDEVD_APPLY_PATCHING_TO_HIDE_PYDEVD_THREADS is set to False, the patching to hide pydevd threads won't be applied. PYDEVD_APPLY_PATCHING_TO_HIDE_PYDEVD_THREADS = os.getenv('PYDEVD_APPLY_PATCHING_TO_HIDE_PYDEVD_THREADS', 'true').lower() in ENV_TRUE_LOWER_VALUES +# If set, configures the server's remote root regardless of what is provided. +PYDEVD_REMOTE_ROOT = os.getenv('PYDEVD_REMOTE_ROOT', None) + EXCEPTION_TYPE_UNHANDLED = 'UNHANDLED' EXCEPTION_TYPE_USER_UNHANDLED = 'USER_UNHANDLED' EXCEPTION_TYPE_HANDLED = 'HANDLED' diff --git a/_pydevd_bundle/pydevd_process_net_command_json.py b/_pydevd_bundle/pydevd_process_net_command_json.py index 92d671b8..888cf411 100644 --- a/_pydevd_bundle/pydevd_process_net_command_json.py +++ b/_pydevd_bundle/pydevd_process_net_command_json.py @@ -29,7 +29,7 @@ from _pydevd_bundle.pydevd_net_command import NetCommand from _pydevd_bundle.pydevd_utils import convert_dap_log_message_to_expression, ScopeRequest from _pydevd_bundle.pydevd_constants import (PY_IMPL_NAME, DebugInfoHolder, PY_VERSION_STR, - PY_IMPL_VERSION_STR, IS_64BIT_PROCESS) + PY_IMPL_VERSION_STR, IS_64BIT_PROCESS, PYDEVD_REMOTE_ROOT) from _pydevd_bundle.pydevd_trace_dispatch import USING_CYTHON from _pydevd_frame_eval.pydevd_frame_eval_main import USING_FRAME_EVAL from _pydevd_bundle.pydevd_comm import internal_get_step_in_targets_json @@ -319,6 +319,9 @@ def on_completions_request(self, py_db, request): self.api.request_completions(py_db, seq, thread_id, frame_id, text, line=line, column=column) def _resolve_remote_root(self, local_root, remote_root): + if PYDEVD_REMOTE_ROOT is not None: + return PYDEVD_REMOTE_ROOT + if remote_root == '.': cwd = os.getcwd() append_pathsep = local_root.endswith('\\') or local_root.endswith('/') diff --git a/pydevd.py b/pydevd.py index fb568a58..fe300183 100644 --- a/pydevd.py +++ b/pydevd.py @@ -56,7 +56,7 @@ clear_cached_thread_id, INTERACTIVE_MODE_AVAILABLE, SHOW_DEBUG_INFO_ENV, NULL, NO_FTRACE, IS_IRONPYTHON, JSON_PROTOCOL, IS_CPYTHON, HTTP_JSON_PROTOCOL, USE_CUSTOM_SYS_CURRENT_FRAMES_MAP, call_only_once, ForkSafeLock, IGNORE_BASENAMES_STARTING_WITH, EXCEPTION_TYPE_UNHANDLED, SUPPORT_GEVENT, - PYDEVD_IPYTHON_COMPATIBLE_DEBUGGING, PYDEVD_IPYTHON_CONTEXT) + PYDEVD_IPYTHON_COMPATIBLE_DEBUGGING, PYDEVD_IPYTHON_CONTEXT, PYDEVD_REMOTE_ROOT) from _pydevd_bundle.pydevd_defaults import PydevdCustomization # Note: import alias used on pydev_monkey. from _pydevd_bundle.pydevd_custom_frames import CustomFramesContainer, custom_frames_container_init from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE, PYDEV_FILE, LIB_FILE, DONT_TRACE_DIRS @@ -3263,6 +3263,8 @@ def _log_initial_info(): pydev_log.debug("Using cython: %s", USING_CYTHON) pydev_log.debug("Using frame eval: %s", USING_FRAME_EVAL) pydev_log.debug("Using gevent mode: %s / imported gevent module support: %s", SUPPORT_GEVENT, bool(pydevd_gevent_integration)) + if PYDEVD_REMOTE_ROOT is not None: + pydev_log.debug("Using remote root: %s", PYDEVD_REMOTE_ROOT) def config(protocol='', debug_mode='', preimport=''): diff --git a/tests_python/test_debugger_json.py b/tests_python/test_debugger_json.py index 85d97af0..741ffb52 100644 --- a/tests_python/test_debugger_json.py +++ b/tests_python/test_debugger_json.py @@ -6633,6 +6633,33 @@ def additional_output_checks(writer, stdout, stderr): writer.finished_ok = True +def test_remote_root_set_in_env_var(case_setup_dap, pyfile): + + def get_environ(self): + env = os.environ.copy() + print(os.path.dirname(self.TEST_FILE)) + env["PYDEVD_REMOTE_ROOT"] = os.path.dirname(self.TEST_FILE) + return env + + @pyfile + def target(): + print('TEST SUCEEDED') # break here + + with case_setup_dap.test_file(target, get_environ=get_environ) as writer: + json_facade = JsonFacade(writer) + + json_facade.write_launch(pathMappings=[{ + 'localRoot': os.path.dirname(writer.TEST_FILE), + 'remoteRoot': "/tmp/somepath", # A path we likely aren't writing to + }]) + break_line = writer.get_line_index_with_content('break here') + json_facade.write_set_breakpoints(break_line) + json_facade.write_make_initial_run() + json_facade.wait_for_thread_stopped(line=break_line) + json_facade.write_continue() + writer.finished_ok = True + + if __name__ == '__main__': pytest.main(['-k', 'test_replace_process', '-s'])