Skip to content

Commit 9db85ed

Browse files
authored
support interpreter paths with spaces (#499)
* support interpreter paths with spaces * use fileToCommandArgumentForPythonExt and add test * fix unnecessary edit * switch to use path.join * error fix * fix path to match desired
1 parent a0bc66d commit 9db85ed

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

src/extension/debugger/adapter/factory.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { Commands, EXTENSION_ROOT_DIR } from '../../common/constants';
2424
import { Common, DebugConfigStrings, Interpreters } from '../../common/utils/localize';
2525
import { IPersistentStateFactory } from '../../common/types';
2626
import { ResolvedEnvironment } from '@vscode/python-extension';
27+
import { fileToCommandArgumentForPythonExt } from '../../common/stringUtils';
2728

2829
// persistent state names, exported to make use of in testing
2930
export enum debugStateKeys {
@@ -74,7 +75,7 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac
7475
sendTelemetryEvent(EventName.DEBUGGER_ATTACH_TO_LOCAL_PROCESS);
7576
}
7677

77-
const executable = command.shift() ?? 'python';
78+
let executable = command.shift() ?? 'python';
7879

7980
// "logToFile" is not handled directly by the adapter - instead, we need to pass
8081
// the corresponding CLI switch when spawning it.
@@ -83,6 +84,7 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac
8384
if (configuration.debugAdapterPath !== undefined) {
8485
const args = command.concat([configuration.debugAdapterPath, ...logArgs]);
8586
traceLog(`DAP Server launched with command: ${executable} ${args.join(' ')}`);
87+
executable = fileToCommandArgumentForPythonExt(executable);
8688
return new DebugAdapterExecutable(executable, args);
8789
}
8890

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

+22-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ suite('Debugging - Adapter Factory', () => {
4141

4242
const nodeExecutable = undefined;
4343
const debugAdapterPath = path.join(EXTENSION_ROOT_DIR, 'bundled', 'libs', 'debugpy', 'adapter');
44-
const pythonPath = path.join('path', 'to', 'python', 'interpreter');
44+
const pythonPath = 'path/to/python/interpreter';
4545
const interpreter = {
4646
architecture: Architecture.Unknown,
4747
path: pythonPath,
@@ -291,6 +291,27 @@ suite('Debugging - Adapter Factory', () => {
291291

292292
assert.deepStrictEqual(descriptor, debugExecutable);
293293
});
294+
test('Add quotes to interpreter path with spaces', async () => {
295+
const customAdapterPath = 'custom/debug/adapter/customAdapterPath';
296+
const session = createSession({ debugAdapterPath: customAdapterPath });
297+
const interpreterPathSpaces = 'path/to/python interpreter with spaces';
298+
const interpreterPathSpacesQuoted = `"${interpreterPathSpaces}"`;
299+
const debugExecutable = new DebugAdapterExecutable(interpreterPathSpacesQuoted, [customAdapterPath]);
300+
301+
getInterpreterDetailsStub.resolves({ path: [interpreterPathSpaces] });
302+
const interpreterSpacePath = {
303+
architecture: Architecture.Unknown,
304+
path: interpreterPathSpaces,
305+
sysPrefix: '',
306+
sysVersion: '',
307+
envType: 'Unknow',
308+
version: new SemVer('3.7.4-test'),
309+
};
310+
resolveEnvironmentStub.withArgs(interpreterPathSpaces).resolves(interpreterSpacePath);
311+
const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable);
312+
313+
assert.deepStrictEqual(descriptor, debugExecutable);
314+
});
294315

295316
test('Use "debugAdapterPython" when specified', async () => {
296317
const session = createSession({ debugAdapterPython: '/bin/custompy' });

0 commit comments

Comments
 (0)