feat(python): support attaching to a running debugpy server over TCP - #10
Closed
pldesch-chift wants to merge 1 commit into
Closed
feat(python): support attaching to a running debugpy server over TCP#10pldesch-chift wants to merge 1 commit into
pldesch-chift wants to merge 1 commit into
Conversation
When a Python process is started with `python -m debugpy --listen <port>`,
the process itself is the DAP server. The previous attach flow would spawn
a second debugpy.adapter process and try to proxy through it, which failed.
This PR adds two fixes:
1. TCP attach mode (useTcpAttach flag)
- New `DapClient.connectTcp(host, port)` static method that opens a
direct TCP connection to a running DAP server instead of spawning
a subprocess.
- New `useTcpAttach` flag on `DapRuntimeConfig`. When set, `attach()`
connects directly over TCP and sends the standard DAP sequence
(initialize → attach → configurationDone) without spawning an adapter.
- `debugpyConfig` sets `useTcpAttach: true`.
2. Race condition fix in initializeAdapter()
- Debugpy fires the DAP `initialized` event during the `initialize`
round-trip, before `waitForInitialized()` had a chance to register
its listener — causing a guaranteed timeout.
- Fixed by registering the `initialized` listener inside
`initializeAdapter()` before sending the `initialize` request, and
storing it as `_initializedPromise` for `waitForInitialized()` to await.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pldesch-chift
marked this pull request as ready for review
April 17, 2026 15:19
5 tasks
Contributor
|
Thank you for you submission ! But I prefer seperating the concerns between the client / the transporter / and the planner that decides the strategy to either attach or launch. See #11 I close this one |
waltoss
added a commit
that referenced
this pull request
Apr 24, 2026
…ctor Refactor DAP attach: transport + connector strategies (replaces #10)
pldesch-chift
pushed a commit
to pldesch-chift/debug-that
that referenced
this pull request
Jun 1, 2026
Replaces the `useTcpAttach` boolean and dual-mode DapClient with two orthogonal abstractions: DapTransport — byte-level I/O (Stdio/Tcp) DapConnector — transport provisioning (SpawnAdapter/TcpAttach) Each DapRuntimeConfig now returns a DapConnectPlan (connector + request args) from launch() and optional attach(). DapSession.launch/attach collapse into a single runHandshake() template, and the debugpy-fires-`initialized`-during-initialize race is now fixed structurally (listener armed before the initialize request is sent) instead of via a separate one-shot promise field. Fixes PR theodo-group#10's issue (adapter-on-adapter when attaching to debugpy): debugpyConfig.attach() returns a TcpAttachConnector, so dbg speaks DAP directly over the socket to the running debugpy — no subprocess in between. Adds an integration test (tests/integration/python/python-attach.test.ts) that spawns `python -m debugpy --listen <port> --wait-for-client`, attaches, and verifies a breakpoint hits. RED on pre-refactor main (times out with the adapter-on-adapter bug), GREEN here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
dbg attach <port> --runtime pythonwas broken. When called, it would:debugpy.adapterprocessattachrequest to connect to the running debugpy serverThis is adapter-on-top-of-adapter — it doesn't work. The new adapter process exited immediately, causing
DAP adapter process terminated.There was also a separate race condition: debugpy fires the
initializedDAP event during theinitializeround-trip, beforewaitForInitialized()had registered its listener — causing a guaranteed timeout.Solution
1. TCP attach mode (
useTcpAttachflag)Added
DapClient.connectTcp(host, port)— a new static constructor that opens a direct TCP connection to a running DAP server instead of spawning a subprocess. WhenuseTcpAttach: trueis set on a runtime config,attach()uses this path and speaks DAP directly over the socket (the same way VS Code does).debugpyConfignow setsuseTcpAttach: true.Usage:
2. Race condition fix in
initializeAdapter()Moved the
initializedevent listener registration to before sending theinitializerequest, storing it as_initializedPromise.waitForInitialized()now awaits this pre-registered promise instead of creating a new listener after the fact.Files changed
src/dap/client.ts— TCP transport support (connectTcp,readLoopTcp, updateddisconnect/writeMessage)src/dap/runtimes/python.ts— adduseTcpAttach: truesrc/dap/runtimes/types.ts— adduseTcpAttach?: booleantoDapRuntimeConfigsrc/dap/session.ts— TCP attach branch +_initializedPromiserace condition fixTesting
Tested end-to-end against a FastAPI/uvicorn app running under debugpy. Breakpoints hit, variables inspectable, step/continue working.
Note: the existing Python integration tests were already failing on
mainbefore these changes (pre-existing issue unrelated to this PR).