Skip to content

Commit e9dc3e8

Browse files
Pavel Minaevint19h
Pavel Minaev
authored andcommitted
Fix #1074: Use "startDebugging" request for subprocesses
Use the request if client advertises the "supportsStartDebuggingRequest" capability.
1 parent 9fd3e72 commit e9dc3e8

File tree

3 files changed

+52
-20
lines changed

3 files changed

+52
-20
lines changed

src/debugpy/adapter/clients.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Capabilities(components.Capabilities):
3030
"supportsRunInTerminalRequest": False,
3131
"supportsMemoryReferences": False,
3232
"supportsArgsCanBeInterpretedByShell": False,
33+
"supportsStartDebuggingRequest": False,
3334
}
3435

3536
class Expectations(components.Capabilities):
@@ -688,11 +689,10 @@ def notify_of_subprocess(self, conn):
688689
self.known_subprocesses.add(conn)
689690
self.session.notify_changed()
690691

691-
for key in "processId", "listen", "preLaunchTask", "postDebugTask":
692+
for key in "processId", "listen", "preLaunchTask", "postDebugTask", "request":
692693
body.pop(key, None)
693694

694695
body["name"] = "Subprocess {0}".format(conn.pid)
695-
body["request"] = "attach"
696696
body["subProcessId"] = conn.pid
697697

698698
for key in "args", "processName", "pythonArgs":
@@ -709,7 +709,14 @@ def notify_of_subprocess(self, conn):
709709
_, port = listener.getsockname()
710710
body["connect"]["port"] = port
711711

712-
self.channel.send_event("debugpyAttach", body)
712+
if self.capabilities["supportsStartDebuggingRequest"]:
713+
self.channel.request("startDebugging", {
714+
"request": "attach",
715+
"configuration": body,
716+
})
717+
else:
718+
body["request"] = "attach"
719+
self.channel.send_event("debugpyAttach", body)
713720

714721

715722
def serve(host, port):

tests/debug/session.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ def __init__(self, debug_config=None):
8484

8585
self.client_id = "vscode"
8686

87+
self.capabilities = {
88+
"pathFormat": "path",
89+
"clientID": self.client_id,
90+
"adapterID": "test",
91+
"linesStartAt1": True,
92+
"columnsStartAt1": True,
93+
"supportsVariableType": True,
94+
"supportsRunInTerminalRequest": True,
95+
"supportsArgsCanBeInterpretedByShell": True,
96+
"supportsStartDebuggingRequest": False,
97+
}
98+
8799
self.debuggee = None
88100
"""psutil.Popen instance for the debuggee process."""
89101

@@ -502,6 +514,10 @@ def _process_request(self, request):
502514
except Exception as exc:
503515
log.swallow_exception('"runInTerminal" failed:')
504516
raise request.cant_handle(str(exc))
517+
elif request.command == "startDebugging":
518+
pid = request("configuration", dict)("subProcessId", int)
519+
watchdog.register_spawn(pid, f"{self.debuggee_id}-subprocess-{pid}")
520+
return {}
505521
else:
506522
raise request.isnt_valid("not supported")
507523

@@ -551,19 +567,7 @@ def _start_channel(self, stream):
551567
)
552568
)
553569

554-
self.request(
555-
"initialize",
556-
{
557-
"pathFormat": "path",
558-
"clientID": self.client_id,
559-
"adapterID": "test",
560-
"linesStartAt1": True,
561-
"columnsStartAt1": True,
562-
"supportsVariableType": True,
563-
"supportsRunInTerminalRequest": True,
564-
"supportsArgsCanBeInterpretedByShell": True,
565-
},
566-
)
570+
self.request("initialize", self.capabilities)
567571

568572
def all_events(self, event, body=some.object):
569573
return [
@@ -783,7 +787,15 @@ def wait_for_stop(
783787
return StopInfo(stopped, frames, tid, fid)
784788

785789
def wait_for_next_subprocess(self):
786-
return Session(self.wait_for_next_event("debugpyAttach"))
790+
message = self.timeline.wait_for_next(timeline.Event("debugpyAttach") | timeline.Request("startDebugging"))
791+
if isinstance(message, timeline.EventOccurrence):
792+
config = message.body
793+
assert "request" in config
794+
elif isinstance(message, timeline.RequestOccurrence):
795+
config = dict(message.body("configuration", dict))
796+
assert "request" not in config
797+
config["request"] = "attach"
798+
return Session(config)
787799

788800
def wait_for_disconnect(self):
789801
self.timeline.wait_until_realized(timeline.Mark("disconnect"), freeze=True)

tests/debugpy/test_multiproc.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import debugpy
1111
import tests
12-
from tests import debug, log
12+
from tests import debug, log, timeline
1313
from tests.debug import runners
1414
from tests.patterns import some
1515

@@ -151,7 +151,8 @@ def grandchild(q, a):
151151

152152

153153
@pytest.mark.parametrize("subProcess", [True, False, None])
154-
def test_subprocess(pyfile, target, run, subProcess):
154+
@pytest.mark.parametrize("method", ["startDebugging", "debugpyAttach", ""])
155+
def test_subprocess(pyfile, target, run, subProcess, method):
155156
@pyfile
156157
def child():
157158
import os
@@ -188,6 +189,8 @@ def parent():
188189
with debug.Session() as parent_session:
189190
backchannel = parent_session.open_backchannel()
190191

192+
if method:
193+
parent_session.capabilities["supportsStartDebuggingRequest"] = (method == "startDebugging")
191194
parent_session.config["preLaunchTask"] = "doSomething"
192195
parent_session.config["postDebugTask"] = "doSomethingElse"
193196
if subProcess is not None:
@@ -200,9 +203,19 @@ def parent():
200203
return
201204

202205
expected_child_config = expected_subprocess_config(parent_session)
203-
child_config = parent_session.wait_for_next_event("debugpyAttach")
206+
207+
if method == "startDebugging":
208+
subprocess_request = parent_session.timeline.wait_for_next(timeline.Request("startDebugging"))
209+
child_config = subprocess_request.arguments("configuration", dict)
210+
del expected_child_config["request"]
211+
else:
212+
child_config = parent_session.wait_for_next_event("debugpyAttach")
213+
214+
child_config = dict(child_config)
204215
child_config.pop("isOutputRedirected", None)
205216
assert child_config == expected_child_config
217+
child_config["request"] = "attach"
218+
206219
parent_session.proceed()
207220

208221
with debug.Session(child_config) as child_session:

0 commit comments

Comments
 (0)