Skip to content

Commit a3d46e4

Browse files
committed
Always quote Python executable path
On Windows, this would cause pahts like "C:\Program Files\" to fail launching the Python command as the blank space was not escaped properly. Add also a unit test to validate this change. Signed-off-by: Francesco Giancane <me@fgiancane8.dev>
1 parent e0ec60c commit a3d46e4

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

src/extension/debugger/adapter/factory.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,20 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac
8080

8181
let executable = command.shift() ?? 'python';
8282

83+
// Always ensure interpreter/command is quoted if necessary. Previously this was
84+
// only done in the debugAdapterPath branch which meant that in the common case
85+
// (using the built‑in adapter path) an interpreter path containing spaces would
86+
// be passed unquoted, resulting in a fork/spawn failure on Windows. See bug
87+
// report for details.
88+
executable = fileToCommandArgumentForPythonExt(executable);
89+
8390
// "logToFile" is not handled directly by the adapter - instead, we need to pass
8491
// the corresponding CLI switch when spawning it.
8592
const logArgs = configuration.logToFile ? ['--log-dir', EXTENSION_ROOT_DIR] : [];
8693

8794
if (configuration.debugAdapterPath !== undefined) {
8895
const args = command.concat([configuration.debugAdapterPath, ...logArgs]);
8996
traceLog(`DAP Server launched with command: ${executable} ${args.join(' ')}`);
90-
executable = fileToCommandArgumentForPythonExt(executable);
9197
return new DebugAdapterExecutable(executable, args);
9298
}
9399

src/test/unittest/adapter/factory.unit.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,23 @@ suite('Debugging - Adapter Factory', () => {
304304

305305
assert.deepStrictEqual(descriptor, debugExecutable);
306306
});
307-
test('Add quotes to interpreter path with spaces', async () => {
307+
test('Add quotes to interpreter path with spaces (default adapter path)', async () => {
308+
const session = createSession({});
309+
const interpreterPathSpaces = 'path/to/python interpreter with spaces';
310+
const interpreterPathSpacesQuoted = `"${interpreterPathSpaces}"`;
311+
const debugExecutable = new DebugAdapterExecutable(interpreterPathSpacesQuoted, [debugAdapterPath]);
312+
313+
getInterpreterDetailsStub.resolves({ path: [interpreterPathSpaces] });
314+
const interpreterSpacePath: PythonEnvironment = createInterpreter(interpreterPathSpaces, '3.7.4-test');
315+
// Add architecture for completeness.
316+
(interpreterSpacePath as any).architecture = Architecture.Unknown;
317+
resolveEnvironmentStub.withArgs(interpreterPathSpaces).resolves(interpreterSpacePath);
318+
const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable);
319+
320+
assert.deepStrictEqual(descriptor, debugExecutable);
321+
});
322+
323+
test('Add quotes to interpreter path with spaces when debugAdapterPath is specified', async () => {
308324
const customAdapterPath = 'custom/debug/adapter/customAdapterPath';
309325
const session = createSession({ debugAdapterPath: customAdapterPath });
310326
const interpreterPathSpaces = 'path/to/python interpreter with spaces';

0 commit comments

Comments
 (0)