diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py index 29b022a4893f..dd9540eb4adf 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py @@ -71,9 +71,12 @@ from _pydev_imps._pydev_saved_modules import threading from _pydev_imps._pydev_saved_modules import time from _pydev_imps._pydev_saved_modules import socket from socket import socket, AF_INET, SOCK_STREAM, SHUT_RD, SHUT_WR, SOL_SOCKET, SO_REUSEADDR, SHUT_RDWR, timeout -from _pydevd_bundle.pydevd_constants import DebugInfoHolder, get_thread_id, IS_JYTHON, IS_PY2, IS_PY3K, \ - IS_PY36_OR_GREATER, STATE_RUN, dict_keys, ASYNC_EVAL_TIMEOUT_SEC, IS_IRONPYTHON, GlobalDebuggerHolder, \ - get_global_debugger, GetGlobalDebugger, set_global_debugger, NEXT_VALUE_SEPARATOR +from _pydevd_bundle.pydevd_constants import DebugInfoHolder, get_thread_id, IS_JYTHON, \ + IS_PY2, IS_PY3K, \ + IS_PY36_OR_GREATER, STATE_RUN, dict_keys, ASYNC_EVAL_TIMEOUT_SEC, IS_IRONPYTHON, \ + GlobalDebuggerHolder, \ + get_global_debugger, GetGlobalDebugger, set_global_debugger, NEXT_VALUE_SEPARATOR, \ + SINGLE_PORT_MODE from _pydev_bundle.pydev_override import overrides import json import weakref @@ -415,10 +418,15 @@ def start_server(port): s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) s.bind(('', port)) - pydevd_log(1, "Bound to port ", str(port)) + effective_port = s.getsockname()[1] + pydevd_log(1, "Bound to port ", str(effective_port)) try: s.listen(1) + if SINGLE_PORT_MODE: + # Output the effective port number to stdout, allowing a client to read + # and connect to it. + sys.stdout.write("Waiting connection on port %s...\n" % effective_port) newSock, _addr = s.accept() pydevd_log(1, "Connection accepted") # closing server socket is not necessary but we don't need it @@ -427,7 +435,7 @@ def start_server(port): return newSock except: - sys.stderr.write("Could not bind to port: %s\n" % (port,)) + sys.stderr.write("Could not bind to port: %s\n" % (effective_port,)) sys.stderr.flush() traceback.print_exc() diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py b/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py index e967ac671e0c..33fdb71bf270 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py @@ -173,6 +173,8 @@ USE_LIB_COPY = SUPPORT_GEVENT and \ USE_LOW_IMPACT_MONITORING = (IS_PY312_OR_GREATER and os.environ.get('USE_LOW_IMPACT_MONITORING', False)) +SINGLE_PORT_MODE = os.environ.get("SINGLE_PORT_MODE") + # The tool name to use in the API calls from PEP 669. PYDEVD_TOOL_NAME = 'pydevd' diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index 0a94596d4a30..98eefb355f87 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -103,6 +103,7 @@ public class PyDebugRunner implements ProgramRunner { protected static final @NonNls String PYCHARM_DEBUG = "PYCHARM_DEBUG"; protected static final @NonNls String USE_LOW_IMPACT_MONITORING = "USE_LOW_IMPACT_MONITORING"; protected static final @NonNls String HALT_VARIABLE_RESOLVE_THREADS_ON_STEP_RESUME = "HALT_VARIABLE_RESOLVE_THREADS_ON_STEP_RESUME"; + protected static final @NonNls String SINGLE_PORT_MODE = "SINGLE_PORT_MODE"; @SuppressWarnings("SpellCheckingInspection") private static final @NonNls String PYTHONPATH_ENV_NAME = "PYTHONPATH"; @@ -704,6 +705,10 @@ public class PyDebugRunner implements ProgramRunner { if (registryManager.is("python.debug.halt.variable.resolve.threads.on.step.resume")) { environmentController.putFixedValue(HALT_VARIABLE_RESOLVE_THREADS_ON_STEP_RESUME, "True"); } + + if (registryManager.is("python.debug.use.single.port")) { + environmentController.putFixedValue(SINGLE_PORT_MODE, "True"); + } } /**