feat(debug): enable Python debug workflow and debug server integration

Adds an end-to-end Python debug workflow for the extension.
Includes a new prepare-debug.ps1 script and a VS Code task.
Extends the Python server and extension to coordinate a debug session and safe startup.

- Add prepare-debug.ps1 and a VS Code task to build the debug bundle
- Enable Python debug wiring in the server and tests
- Ensure a single stable Python debug session during startup
This commit is contained in:
Christoph Brandau
2026-08-17 11:02:22 +02:00
parent 35a4357551
commit 33cf282b0a
14 changed files with 349 additions and 73 deletions
+35 -12
View File
@@ -10,13 +10,21 @@
"type": "extensionHost", "type": "extensionHost",
"request": "launch", "request": "launch",
"runtimeExecutable": "${execPath}", "runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"], "args": [
"outFiles": ["${workspaceFolder}/client/**/*.js"], "--extensionDevelopmentPath=${env:TEMP}/nx-post-support-vscode-debug",
"${env:TEMP}/nx-post-support-vscode-debug",
"${env:TEMP}/nx-post-support-vscode-debug/test/test.tcl"
],
"cwd": "${env:TEMP}/nx-post-support-vscode-debug",
"outFiles": ["${env:TEMP}/nx-post-support-vscode-debug/dist/**/*.js"],
"sourceMaps": true,
"resolveSourceMapLocations": [
"${env:TEMP}/nx-post-support-vscode-debug/dist/**/*.js",
"!**/node_modules/**"
],
"skipFiles": ["<node_internals>/**"],
"autoAttachChildProcesses": true, "autoAttachChildProcesses": true,
"preLaunchTask": { "preLaunchTask": "NX Post Support: Compile Debug"
"type": "npm",
"script": "watch"
}
}, },
{ {
"name": "Python Attach", "name": "Python Attach",
@@ -34,10 +42,24 @@
"name": "Debug Extension (hidden)", "name": "Debug Extension (hidden)",
"type": "extensionHost", "type": "extensionHost",
"request": "launch", "request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"], "runtimeExecutable": "${execPath}",
"outFiles": ["${workspaceFolder}/client/**/*.js"], "args": [
"--extensionDevelopmentPath=${env:TEMP}/nx-post-support-vscode-debug",
"${env:TEMP}/nx-post-support-vscode-debug",
"${env:TEMP}/nx-post-support-vscode-debug/test/test.tcl"
],
"cwd": "${env:TEMP}/nx-post-support-vscode-debug",
"outFiles": ["${env:TEMP}/nx-post-support-vscode-debug/dist/**/*.js"],
"sourceMaps": true,
"resolveSourceMapLocations": [
"${env:TEMP}/nx-post-support-vscode-debug/dist/**/*.js",
"!**/node_modules/**"
],
"skipFiles": ["<node_internals>/**"],
"env": { "env": {
"USE_DEBUGPY": "True" "USE_DEBUGPY": "True",
"NXPS_DEBUG_HOST": "127.0.0.1",
"NXPS_DEBUG_PORT": "5678"
}, },
"presentation": { "presentation": {
"hidden": true, "hidden": true,
@@ -49,8 +71,9 @@
"name": "Python debug server (hidden)", "name": "Python debug server (hidden)",
"type": "debugpy", "type": "debugpy",
"request": "attach", "request": "attach",
"listen": { "host": "localhost", "port": 5678 }, "listen": { "host": "127.0.0.1", "port": 5678 },
"justMyCode": true, "justMyCode": false,
"logToFile": true,
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "", "group": "",
@@ -63,7 +86,7 @@
"name": "Debug Extension and Python", "name": "Debug Extension and Python",
"configurations": ["Python debug server (hidden)", "Debug Extension (hidden)"], "configurations": ["Python debug server (hidden)", "Debug Extension (hidden)"],
"stopAll": true, "stopAll": true,
"preLaunchTask": "npm: watch", "preLaunchTask": "NX Post Support: Compile Debug",
"presentation": { "presentation": {
"hidden": false, "hidden": false,
"group": "", "group": "",
+57
View File
@@ -0,0 +1,57 @@
param(
[Parameter(Mandatory = $true)]
[string]$WorkspaceRoot,
[Parameter(Mandatory = $true)]
[string]$DebugRoot
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function ConvertFrom-ExtendedWindowsPath {
param([string]$Path)
if ($Path.StartsWith("\\?\UNC\", [System.StringComparison]::OrdinalIgnoreCase)) {
return "\\" + $Path.Substring(8)
}
if ($Path.StartsWith("\\?\", [System.StringComparison]::OrdinalIgnoreCase)) {
return $Path.Substring(4)
}
return $Path
}
$workspacePath = ConvertFrom-ExtendedWindowsPath $WorkspaceRoot
$workspaceItem = Get-Item -LiteralPath $workspacePath
if (-not $workspaceItem.PSIsContainer) {
throw "Workspace root is not a directory: $workspacePath"
}
$workspacePath = $workspaceItem.FullName
$debugPath = ConvertFrom-ExtendedWindowsPath $DebugRoot
$tempPath = [System.IO.Path]::GetFullPath([System.IO.Path]::GetTempPath()).TrimEnd("\")
$debugParent = [System.IO.Path]::GetFullPath((Split-Path -Parent $debugPath)).TrimEnd("\")
if (-not $debugParent.Equals($tempPath, [System.StringComparison]::OrdinalIgnoreCase)) {
throw "Debug alias must be located directly below the user temp directory: $debugPath"
}
if (Test-Path -LiteralPath $debugPath) {
$debugItem = Get-Item -LiteralPath $debugPath -Force
if ($debugItem.LinkType -ne "Junction") {
throw "Debug alias exists but is not a junction: $debugPath"
}
$currentTarget = (Get-Item -LiteralPath $debugItem.Target).FullName
if (-not $currentTarget.Equals($workspacePath, [System.StringComparison]::OrdinalIgnoreCase)) {
# Removing a junction removes only the link, never the target directory.
Remove-Item -LiteralPath $debugPath -Force
}
}
if (-not (Test-Path -LiteralPath $debugPath)) {
New-Item -ItemType Junction -Path $debugPath -Target $workspacePath | Out-Null
}
Write-Output "Debug extension path: $debugPath -> $workspacePath"
& npm.cmd --prefix $workspacePath run compile:debug
exit $LASTEXITCODE
+26
View File
@@ -0,0 +1,26 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "NX Post Support: Compile Debug",
"type": "process",
"command": "powershell.exe",
"args": [
"-NoLogo",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"& { param([string]$WorkspaceRoot, [string]$DebugRoot); $scriptRoot = $WorkspaceRoot; if ($scriptRoot.StartsWith('\\\\?\\')) { $scriptRoot = $scriptRoot.Substring(4) }; & (Join-Path $scriptRoot '.vscode\\prepare-debug.ps1') -WorkspaceRoot $WorkspaceRoot -DebugRoot $DebugRoot; exit $LASTEXITCODE }",
"${workspaceFolder}",
"${env:TEMP}\\nx-post-support-vscode-debug"
],
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"clear": true
}
}
]
}
+24 -1
View File
@@ -20,7 +20,7 @@ A comprehensive VS Code extension providing language support for NX CAM postproc
## Installation ## Installation
1. Install from the VS Code Marketplace 1. Install from the VS Code Marketplace
2. Install Python 3.8 or higher 2. Install Python 3.11 or higher
3. Open any `.cdl`, `.tcl`, or `.def` file 3. Open any `.cdl`, `.tcl`, or `.def` file
4. The extension will automatically activate and provide language support 4. The extension will automatically activate and provide language support
@@ -43,6 +43,29 @@ Simply open any supported file type and enjoy:
- Hover information - Hover information
- Signature help while entering procedure arguments - Signature help while entering procedure arguments
## Development and debugging
Install the root and client dependencies before the first debug session:
```powershell
npm install
npm install --prefix client
```
Use one of the checked-in VS Code launch configurations:
- **Run Extension** debugs the TypeScript extension host.
- **Debug Extension and Python** debugs both the TypeScript extension and the
Python language server. This is the recommended configuration for LSP work.
- **Python Attach** attaches manually to an already running Python process.
The launch configuration creates a fresh non-minified bundle with embedded
source maps and opens `test/test.tcl` so the extension activates immediately.
For combined debugging, the Python adapter listens on `127.0.0.1:5678`; the
language server waits for that adapter before initialization. The NX
Postprocessor Support output channel reports `Python debug mode: enabled` and
shows `_debug_server.py` in the server command when the debug path is active.
## Contributing ## Contributing
This extension is actively maintained. For issues or feature requests, please visit our [repository](https://git.cbsk-tech.de/Christoph/nx_post_support.git). This extension is actively maintained. For issues or feature requests, please visit our [repository](https://git.cbsk-tech.de/Christoph/nx_post_support.git).
+22
View File
@@ -14,6 +14,7 @@
"vscode-languageclient": "^9.0.1" "vscode-languageclient": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^11.0.4",
"@types/node": "^22.10.5", "@types/node": "^22.10.5",
"@types/vscode": "^1.96.0" "@types/vscode": "^1.96.0"
}, },
@@ -21,6 +22,27 @@
"vscode": "^1.96.0" "vscode": "^1.96.0"
} }
}, },
"node_modules/@types/fs-extra": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
"integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/jsonfile": "*",
"@types/node": "*"
}
},
"node_modules/@types/jsonfile": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz",
"integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.10.5", "version": "22.10.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
+1
View File
@@ -12,6 +12,7 @@
"vscode-languageclient": "^9.0.1" "vscode-languageclient": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^11.0.4",
"@types/node": "^22.10.5", "@types/node": "^22.10.5",
"@types/vscode": "^1.96.0" "@types/vscode": "^1.96.0"
} }
+51 -30
View File
@@ -39,13 +39,26 @@ async function createServer(
initializationOptions: IInitOptions initializationOptions: IInitOptions
): Promise<LanguageClient> { ): Promise<LanguageClient> {
const command = settings.interpreter[0] const command = settings.interpreter[0]
if (!command) {
throw new Error("No Python interpreter is configured for the language server.")
}
const cwd = settings.cwd const cwd = settings.cwd
// Set debugger path needed for debugging python code. // Set debugger path needed for debugging python code.
const newEnv = { ...process.env } const newEnv = { ...process.env }
const debuggerPath = await getDebuggerPath()
const isDebugScript = await fsapi.pathExists(DEBUG_SERVER_SCRIPT_PATH) const isDebugScript = await fsapi.pathExists(DEBUG_SERVER_SCRIPT_PATH)
if (newEnv.USE_DEBUGPY && debuggerPath) { const debugRequested = newEnv.USE_DEBUGPY?.toLowerCase() === "true"
if (debugRequested && !isDebugScript) {
throw new Error(`Python debug bootstrap not found: ${DEBUG_SERVER_SCRIPT_PATH}`)
}
const debuggerPath = debugRequested ? await getDebuggerPath() : undefined
if (debugRequested && !debuggerPath) {
throw new Error(
"Python debugging was requested, but the Python Debugger extension did not provide debugpy."
)
}
if (debugRequested && debuggerPath) {
newEnv.DEBUGPY_PATH = debuggerPath newEnv.DEBUGPY_PATH = debuggerPath
} else { } else {
newEnv.USE_DEBUGPY = "False" newEnv.USE_DEBUGPY = "False"
@@ -57,10 +70,13 @@ async function createServer(
// Set notification type // Set notification type
newEnv.LS_SHOW_NOTIFICATION = settings.showNotifications newEnv.LS_SHOW_NOTIFICATION = settings.showNotifications
const args = const serverScript = debugRequested ? DEBUG_SERVER_SCRIPT_PATH : SERVER_SCRIPT_PATH
newEnv.USE_DEBUGPY === "False" || !isDebugScript const interpreterArgs = settings.interpreter.slice(1)
? settings.interpreter.slice(1).concat([SERVER_SCRIPT_PATH]) if (debugRequested && !interpreterArgs.includes("-Xfrozen_modules=off")) {
: settings.interpreter.slice(1).concat([DEBUG_SERVER_SCRIPT_PATH]) interpreterArgs.push("-Xfrozen_modules=off")
}
const args = interpreterArgs.concat([serverScript])
traceInfo(`Python debug mode: ${debugRequested ? "enabled" : "disabled"}`)
traceInfo(`Server run command: ${[command, ...args].join(" ")}`) traceInfo(`Server run command: ${[command, ...args].join(" ")}`)
const serverOptions: ServerOptions = { const serverOptions: ServerOptions = {
@@ -108,35 +124,40 @@ export async function restartServer(
const projectRoot = await getProjectRoot() const projectRoot = await getProjectRoot()
const workspaceSetting = await getWorkspaceSettings(serverId, projectRoot, true) const workspaceSetting = await getWorkspaceSettings(serverId, projectRoot, true)
const newLSClient = await createServer(workspaceSetting, serverId, serverName, outputChannel, {
settings: await getExtensionSettings(serverId, true),
globalSettings: await getGlobalSettings(serverId, false)
})
traceInfo(`Server: Start requested.`)
_disposables.push(
newLSClient.onDidChangeState((e) => {
switch (e.newState) {
case State.Stopped:
traceVerbose(`Server State: Stopped`)
break
case State.Starting:
traceVerbose(`Server State: Starting`)
break
case State.Running:
traceVerbose(`Server State: Running`)
break
}
})
)
try { try {
const newLSClient = await createServer(
workspaceSetting,
serverId,
serverName,
outputChannel,
{
settings: await getExtensionSettings(serverId, true),
globalSettings: await getGlobalSettings(serverId, false)
}
)
traceInfo(`Server: Start requested.`)
_disposables.push(
newLSClient.onDidChangeState((e) => {
switch (e.newState) {
case State.Stopped:
traceVerbose(`Server State: Stopped`)
break
case State.Starting:
traceVerbose(`Server State: Starting`)
break
case State.Running:
traceVerbose(`Server State: Running`)
break
}
})
)
await newLSClient.start() await newLSClient.start()
const level = getLSClientTraceLevel(outputChannel.logLevel, env.logLevel)
await newLSClient.setTrace(level)
return newLSClient
} catch (ex) { } catch (ex) {
traceError(`Server: Start failed: ${ex}`) traceError(`Server: Start failed: ${ex}`)
disposeServerResources() disposeServerResources()
return undefined return undefined
} }
const level = getLSClientTraceLevel(outputChannel.logLevel, env.logLevel)
await newLSClient.setTrace(level)
return newLSClient
} }
+18 -3
View File
@@ -38,6 +38,7 @@ export async function activate(context: vscode.ExtensionContext) {
const serverInfo = loadServerDefaults() const serverInfo = loadServerDefaults()
const serverName = serverInfo.name const serverName = serverInfo.name
const serverId = serverInfo.module const serverId = serverInfo.module
const pythonDebugMode = process.env.USE_DEBUGPY?.toLowerCase() === "true"
// Setup logging // Setup logging
const outputChannel = createOutputChannel(serverName) const outputChannel = createOutputChannel(serverName)
@@ -101,10 +102,15 @@ export async function activate(context: vscode.ExtensionContext) {
return runServerQueue return runServerQueue
} }
if (!pythonDebugMode) {
context.subscriptions.push(
onDidChangePythonInterpreter(async () => {
await runServer()
})
)
}
context.subscriptions.push( context.subscriptions.push(
onDidChangePythonInterpreter(async () => {
await runServer()
}),
onDidChangeConfiguration(async (e: vscode.ConfigurationChangeEvent) => { onDidChangeConfiguration(async (e: vscode.ConfigurationChangeEvent) => {
if (checkIfConfigurationChanged(e, serverId)) { if (checkIfConfigurationChanged(e, serverId)) {
await runServer() await runServer()
@@ -116,6 +122,15 @@ export async function activate(context: vscode.ExtensionContext) {
) )
setImmediate(async () => { setImmediate(async () => {
if (pythonDebugMode) {
// A debugpy listen session is attached to exactly one process. Do not
// subscribe to interpreter changes during startup, as the Python
// extension can emit a duplicate event and restart that process.
traceLog("Python debug mode: starting one stable server session")
await runServer()
return
}
const interpreter = getInterpreterFromSetting(serverId) const interpreter = getInterpreterFromSetting(serverId)
if (interpreter === undefined || interpreter.length === 0) { if (interpreter === undefined || interpreter.length === 0) {
traceLog(`Python extension loading`) traceLog(`Python extension loading`)
+4 -2
View File
@@ -1,19 +1,21 @@
const esbuild = require("esbuild") const esbuild = require("esbuild")
const path = require("path")
const production = process.argv.includes("--production") const production = process.argv.includes("--production")
const watch = process.argv.includes("--watch") const watch = process.argv.includes("--watch")
async function main() { async function main() {
const ctx = await esbuild.context({ const ctx = await esbuild.context({
absWorkingDir: __dirname,
entryPoints: ["client/src/extension.ts"], entryPoints: ["client/src/extension.ts"],
bundle: true, bundle: true,
format: "cjs", format: "cjs",
minify: production, minify: production,
sourcemap: !production, sourcemap: !production,
sourcesContent: false, sourcesContent: !production,
platform: "node", platform: "node",
// outdir: "out", // outdir: "out",
outfile: "./dist/extension.js", outfile: path.join(__dirname, "dist", "extension.js"),
external: ["vscode"], external: ["vscode"],
logLevel: "silent", logLevel: "silent",
plugins: [ plugins: [
+1
View File
@@ -124,6 +124,7 @@
}, },
"scripts": { "scripts": {
"compile": "node esbuild.js --production", "compile": "node esbuild.js --production",
"compile:debug": "node esbuild.js",
"watch": "node esbuild.js --watch", "watch": "node esbuild.js --watch",
"package": "node esbuild.js --production" "package": "node esbuild.js --production"
}, },
+47 -24
View File
@@ -6,6 +6,7 @@ import os
import pathlib import pathlib
import runpy import runpy
import sys import sys
import time
def update_sys_path(path_to_add: str) -> None: def update_sys_path(path_to_add: str) -> None:
@@ -14,10 +15,43 @@ def update_sys_path(path_to_add: str) -> None:
sys.path.append(path_to_add) sys.path.append(path_to_add)
# Ensure debugger is loaded before we load anything else, to debug initialization. def _debug_endpoint() -> tuple[str, int]:
debugger_path = os.getenv("DEBUGPY_PATH", None) host = os.getenv("NXPS_DEBUG_HOST", "127.0.0.1")
if debugger_path: raw_port = os.getenv("NXPS_DEBUG_PORT", "5678")
if debugger_path.endswith("debugpy"): try:
port = int(raw_port)
except ValueError as error:
raise RuntimeError(f"Invalid NXPS_DEBUG_PORT: {raw_port!r}") from error
if not 1 <= port <= 65535:
raise RuntimeError(f"NXPS_DEBUG_PORT is outside the valid range: {port}")
return host, port
def _connect_debugger(debugpy, host: str, port: int, timeout: float = 15.0) -> None:
deadline = time.monotonic() + timeout
last_error: OSError | None = None
while time.monotonic() < deadline:
try:
debugpy.connect((host, port))
debugpy.wait_for_client()
return
except (ConnectionRefusedError, OSError) as error:
last_error = error
time.sleep(0.25)
raise RuntimeError(
f"Could not connect debugpy to {host}:{port} within {timeout:.0f} seconds"
) from last_error
def main() -> None:
# Ensure debugger is loaded before we load anything else, so server
# initialization and module-level feature registration can be debugged.
debugger_path = os.getenv("DEBUGPY_PATH")
if not debugger_path:
raise RuntimeError("DEBUGPY_PATH is missing in Python debug mode")
if pathlib.Path(debugger_path).name.casefold() == "debugpy":
debugger_path = os.fspath(pathlib.Path(debugger_path).parent) debugger_path = os.fspath(pathlib.Path(debugger_path).parent)
update_sys_path(debugger_path) update_sys_path(debugger_path)
@@ -25,25 +59,14 @@ if debugger_path:
# pylint: disable=wrong-import-position,import-error # pylint: disable=wrong-import-position,import-error
import debugpy import debugpy
# 5678 is the default port, If you need to change it update it here host, port = _debug_endpoint()
# and in launch.json. print(f"debugpy: waiting for VS Code at {host}:{port}", file=sys.stderr)
# Connecting requires the "Python debug server" listener (launch.json) to be _connect_debugger(debugpy, host, port)
# up first. If it isn't (e.g. wrong launch config was used), don't crash the print("debugpy: VS Code attached; starting language server", file=sys.stderr)
# whole language server - just continue running without the debugger attached.
try:
debugpy.connect(5678)
except (ConnectionRefusedError, OSError) as exc:
print(
f"debugpy: could not connect to debug adapter on port 5678 "
f"({exc}); continuing without debugging.",
file=sys.stderr,
)
# This will ensure that execution is paused as soon as the debugger server_path = os.fspath(pathlib.Path(__file__).parent / "lsp_server.py")
# connects to VS Code. If you don't want to pause here comment this runpy.run_path(server_path, run_name="__main__")
# line and set breakpoints as appropriate.
# debugpy.breakpoint()
SERVER_PATH = os.fspath(pathlib.Path(__file__).parent / "lsp_server.py")
# NOTE: Set breakpoint in `lsp_server.py` before continuing. if __name__ == "__main__":
runpy.run_path(SERVER_PATH, run_name="__main__") main()
+7 -1
View File
@@ -704,7 +704,13 @@ def initialized(_params: lsp.InitializedParams):
def index_workspace(): def index_workspace():
try: try:
root = LSP_SERVER.workspace.root_path try:
root = LSP_SERVER.workspace.root_path
except RuntimeError:
root = None
if not root:
log_to_output("Background indexing skipped: no workspace folder is open.")
return
log_to_output("Background indexing started...") log_to_output("Background indexing started...")
root_path = pathlib.Path(root) root_path = pathlib.Path(root)
skipped_directories = { skipped_directories = {
@@ -0,0 +1,53 @@
import sys
from pathlib import Path
import pytest
THIS_DIR = Path(__file__).parent
SRC_DIR = THIS_DIR.parent.parent / "src"
if str(SRC_DIR) not in sys.path:
sys.path.insert(0, str(SRC_DIR))
import _debug_server
def test_debug_endpoint_defaults(monkeypatch):
monkeypatch.delenv("NXPS_DEBUG_HOST", raising=False)
monkeypatch.delenv("NXPS_DEBUG_PORT", raising=False)
assert _debug_server._debug_endpoint() == ("127.0.0.1", 5678)
@pytest.mark.parametrize("port", ["invalid", "0", "65536"])
def test_debug_endpoint_rejects_invalid_port(monkeypatch, port):
monkeypatch.setenv("NXPS_DEBUG_PORT", port)
with pytest.raises(RuntimeError):
_debug_server._debug_endpoint()
def test_connect_debugger_retries_until_adapter_is_ready(monkeypatch):
class FakeDebugpy:
def __init__(self):
self.connect_calls = 0
self.wait_calls = 0
def connect(self, endpoint):
assert endpoint == ("127.0.0.1", 5678)
self.connect_calls += 1
if self.connect_calls < 3:
raise ConnectionRefusedError("listener is starting")
def wait_for_client(self):
self.wait_calls += 1
fake_debugpy = FakeDebugpy()
monkeypatch.setattr(_debug_server.time, "sleep", lambda _seconds: None)
_debug_server._connect_debugger(
fake_debugpy, "127.0.0.1", 5678, timeout=1.0
)
assert fake_debugpy.connect_calls == 3
assert fake_debugpy.wait_calls == 1
+3
View File
@@ -114,3 +114,6 @@ proc SERVICE_get_tool_data {} {
LIB_GE_command_buffer_edit_replace MOM_end_of_program_LIB END_OF_PROGRAM @END_OF_PROG { LIB_GE_command_buffer_edit_replace MOM_end_of_program_LIB END_OF_PROGRAM @END_OF_PROG {
MOM_do_template "end_of_program_rewind" MOM_do_template "end_of_program_rewind"
} EndOfProgramRewind } EndOfProgramRewind
SERVICE_remove_file "test"