Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 14 additions & 15 deletions src/debugpy/server/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,9 @@ def _settrace(*args, **kwargs):
# The stdin in notification is not acted upon in debugpy, so, disable it.
kwargs.setdefault("notify_stdin", False)
try:
return pydevd.settrace(*args, **kwargs)
pydevd.settrace(*args, **kwargs)
except Exception:
raise
else:
_settrace.called = True


_settrace.called = False


def ensure_logging():
Expand Down Expand Up @@ -78,9 +73,6 @@ def log_to(path):


def configure(properties=None, **kwargs):
if _settrace.called:
raise RuntimeError("debug adapter is already running")

ensure_logging()
log.debug("configure{0!r}", (properties, kwargs))

Expand All @@ -104,9 +96,6 @@ def configure(properties=None, **kwargs):

def _starts_debugging(func):
def debug(address, **kwargs):
if _settrace.called:
raise RuntimeError("this process already has a debug adapter")

try:
_, port = address
except Exception:
Expand All @@ -116,7 +105,7 @@ def debug(address, **kwargs):
port.__index__() # ensure it's int-like
except Exception:
raise ValueError("expected port or (host, port)")
if not (0 <= port < 2 ** 16):
if not (0 <= port < 2**16):
raise ValueError("invalid port number")

ensure_logging()
Expand Down Expand Up @@ -150,10 +139,14 @@ def listen(address, settrace_kwargs, in_process_debug_adapter=False):
# Errors below are logged with level="info", because the caller might be catching
# and handling exceptions, and we don't want to spam their stderr unnecessarily.

if listen.called:
# Multiple calls to listen() cause the debuggee to hang
raise RuntimeError("debugpy.listen() has already been called on this process")

if in_process_debug_adapter:
host, port = address
log.info("Listening: pydevd without debugpy adapter: {0}:{1}", host, port)
settrace_kwargs['patch_multiprocessing'] = False
settrace_kwargs["patch_multiprocessing"] = False
_settrace(
host=host,
port=port,
Expand Down Expand Up @@ -218,7 +211,10 @@ def listen(address, settrace_kwargs, in_process_debug_adapter=False):
try:
global _adapter_process
_adapter_process = subprocess.Popen(
adapter_args, close_fds=True, creationflags=creationflags, env=python_env
adapter_args,
close_fds=True,
creationflags=creationflags,
env=python_env,
)
if os.name == "posix":
# It's going to fork again to daemonize, so we need to wait on it to
Expand Down Expand Up @@ -288,8 +284,11 @@ def listen(address, settrace_kwargs, in_process_debug_adapter=False):
**settrace_kwargs
)
log.info("pydevd is connected to adapter at {0}:{1}", server_host, server_port)
listen.called = True
return client_host, client_port

listen.called = False


@_starts_debugging
def connect(address, settrace_kwargs, access_token=None):
Expand Down
45 changes: 45 additions & 0 deletions tests/debugpy/test_attach.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,51 @@ def code_to_debug():

session.request_continue()

def test_multiple_listen_raises_exception(pyfile):
@pyfile
def code_to_debug():
import debuggee
import debugpy
import sys

from debuggee import backchannel

debuggee.setup()
_, host, port = sys.argv
port = int(port)
debugpy.listen(address=(host, port))
try:
debugpy.listen(address=(host, port))
except RuntimeError:
backchannel.send("listen_exception")

debugpy.wait_for_client()
debugpy.breakpoint()
print("break") # @breakpoint

host, port = runners.attach_connect.host, runners.attach_connect.port
with debug.Session() as session:
backchannel = session.open_backchannel()
session.spawn_debuggee(
[
code_to_debug,
host,
port,
]
)

session.wait_for_adapter_socket()
session.expect_server_socket()
session.connect_to_adapter((host, port))
with session.request_attach():
pass

session.wait_for_stop(
expected_frames=[some.dap.frame(code_to_debug, "breakpoint")]
)
assert backchannel.receive() == "listen_exception"
session.request_continue()


@pytest.mark.parametrize("run", runners.all_attach_connect)
def test_reattach(pyfile, target, run):
Expand Down
Loading