When trying to attach a process to the debugpy, the expected messages sequence is the following:
client -> debugpy: initialize request client <- debugpy: intialize response client <- debugpy: initialize event client -> debugpy: attach request client -> debugpy: setBreakpoints request client <- debugpy: setBreakpoints response client -> debugpy: configurationDone request client <- debugpy: configurationDone response client <- debugpy: attach response
This is different from the messages sequence required to attach a process to PTVSD:
client -> PTVSD: initialize request client <- PTVSD: initialize response client <- PTVSD: initialize event client -> PTVSD: attach request client <- PTVSD: attach response client -> PTVSD: setBreakpoints request client <- PTVSD: setBreakpoints response client -> PTVSD: configurationDone request client <- PTVSD: configurationDone response
The sequence should be the same as that of PTVSD, that is,
attach response should be sent once the process is attached instead of waiting for
configurationDone request. Besides, this seems to break the "reply - response" pattern from the Debug Adapter protocol, and is not consistent with the initialization sequence described on this page
Build xeus-python from this branch: jupyter-xeus/xeus-python#329 Try to run the bugger
@JohanMabille It's a legal sequence, but it's up to the debug adapter to signal the "initialized" event when the conditions are met. In case of debugpy, the conditions aren't met until after you issue the "launch" or "attach" request.
The reason why it needs it is because the adapter doesn't handle breakpoints - the debug server does. But, there's no debug server until one is either spawned (if "launch") or attached to. If "setBreakpoints" were an event, it could be deferred and propagated when the server is there - but it's a request, requiring a response, so you'd just end up with a deadlock where the client is waiting for a response, and the adapter is waiting for "launch" or "attach".
This is different from ptvsd 4, because in that one, the debug adapter proper was not a part of ptvsd at all, but rather a bunch of TypeScript code in the VSCode extension - ptvsd itself was strictly a debug server, and didn't meaningfully handle "launch" or "attach" at all, since, by definition, it's already in the process it's trying to debug. The old adapter was aware of ptvsd's non-coformance idiosyncracies, and massaged them into something that VSCode could handle; in particular, it would not send "initialized" event until it received "launch", and spawned the ptvsd server (and thus ready to receive "setBreakpoints").
The new adapter that's a part of debugpy itself does the same thing. Previously, if you were using ptvsd directly as a client - e.g. by attaching to the socket - you were skipping the old adapter, and thus getting ptvsd's broken implementation of DAP. But now you're always going via the adapter, hence why you are seeing different behavior.
DAP spec needs to be updated to reflect the diagram linked above. There was an issue about that on their issue tracker somewhere. But in any case, the client is supposed to follow the adapter lead here - it's up to the adapter to decide which sequence is more appropriate to its implementation (whether it's because that's the only way to do it, or because it's just easier). A conforming client should wait until the "initialized" event is received before sending "setBreakpoints", and should be able to handle either sequence in the diagram - meaning that it cannot wait for "launch" or "attach" response before sending "setBreakpoints" and/or "configurationDone". This is not something that's clear from the DAP spec by itself, but it doesn't contradict it, either.
(@weinand, please correct me if anything is wrong in the above.)
From our perspective, which sequence debugpy implements is an implementation detail that can change at any time in the future, and should not be relied upon. The only guarantee that we make here is conformance to the spec as clarified by the diagram.