Skip to content
8 changes: 7 additions & 1 deletion src/extension/debugger/adapter/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,20 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac

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

// Always ensure interpreter/command is quoted if necessary. Previously this was
// only done in the debugAdapterPath branch which meant that in the common case
// (using the built‑in adapter path) an interpreter path containing spaces would
// be passed unquoted, resulting in a fork/spawn failure on Windows. See bug
// report for details.
executable = fileToCommandArgumentForPythonExt(executable);

// "logToFile" is not handled directly by the adapter - instead, we need to pass
// the corresponding CLI switch when spawning it.
const logArgs = configuration.logToFile ? ['--log-dir', EXTENSION_ROOT_DIR] : [];

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

Expand Down
18 changes: 17 additions & 1 deletion src/test/unittest/adapter/factory.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,23 @@ suite('Debugging - Adapter Factory', () => {

assert.deepStrictEqual(descriptor, debugExecutable);
});
test('Add quotes to interpreter path with spaces', async () => {
test('Add quotes to interpreter path with spaces (default adapter path)', async () => {
const session = createSession({});
const interpreterPathSpaces = 'path/to/python interpreter with spaces';
const interpreterPathSpacesQuoted = `"${interpreterPathSpaces}"`;
const debugExecutable = new DebugAdapterExecutable(interpreterPathSpacesQuoted, [debugAdapterPath]);

getInterpreterDetailsStub.resolves({ path: [interpreterPathSpaces] });
const interpreterSpacePath: PythonEnvironment = createInterpreter(interpreterPathSpaces, '3.7.4-test');
// Add architecture for completeness.
(interpreterSpacePath as any).architecture = Architecture.Unknown;
resolveEnvironmentStub.withArgs(interpreterPathSpaces).resolves(interpreterSpacePath);
const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable);

assert.deepStrictEqual(descriptor, debugExecutable);
});

test('Add quotes to interpreter path with spaces when debugAdapterPath is specified', async () => {
const customAdapterPath = 'custom/debug/adapter/customAdapterPath';
const session = createSession({ debugAdapterPath: customAdapterPath });
const interpreterPathSpaces = 'path/to/python interpreter with spaces';
Expand Down
Loading