Skip to content

Commit eaef59e

Browse files
committed
Fix python.interpreterPath resolving wrong interpreter in tasks.json when other variables are present
Signed-off-by: Mohit Yadav <ymohit799057@gmail.com>
1 parent 82940c9 commit eaef59e

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

src/client/interpreter/interpreterPathCommand.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ export class InterpreterPathCommand implements IExtensionSingleActivationService
4343
if (Array.isArray(workspace.workspaceFolders) && workspace.workspaceFolders.length > 0) {
4444
workspaceFolder = workspace.workspaceFolders[0].uri.fsPath;
4545
}
46+
} else if (
47+
Array.isArray(args) &&
48+
Array.isArray(workspace.workspaceFolders) &&
49+
workspace.workspaceFolders.length === 1
50+
) {
51+
// tasks.json case: args[1] isn't always populated by VS Code's task variable resolver
52+
// when other variable kinds (${input:...}, ${env:...}) are resolved alongside this
53+
// command in the same task. Single-root workspace is unambiguous, so fall back to it
54+
// instead of resolving the global interpreter. Multi-root stays undefined below --
55+
// we can't guess which folder without args.
56+
workspaceFolder = workspace.workspaceFolders[0].uri.fsPath;
4657
} else {
4758
workspaceFolder = undefined;
4859
}

src/test/interpreters/interpreterPathCommand.unit.test.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { assert, expect } from 'chai';
77
import * as sinon from 'sinon';
8-
import { anything, instance, mock, when } from 'ts-mockito';
8+
import { anything, instance, mock, reset, when } from 'ts-mockito';
99
import * as TypeMoq from 'typemoq';
1010
import { Uri } from 'vscode';
1111
import { IDisposable } from '../../client/common/types';
@@ -14,6 +14,7 @@ import { InterpreterPathCommand } from '../../client/interpreter/interpreterPath
1414
import { IInterpreterService } from '../../client/interpreter/contracts';
1515
import { PythonEnvironment } from '../../client/pythonEnvironments/info';
1616
import * as workspaceApis from '../../client/common/vscodeApis/workspaceApis';
17+
import { mockedVSCodeNamespaces } from '../vscode-mock';
1718

1819
suite('Interpreter Path Command', () => {
1920
let interpreterService: IInterpreterService;
@@ -30,6 +31,7 @@ suite('Interpreter Path Command', () => {
3031

3132
teardown(() => {
3233
sinon.restore();
34+
reset(mockedVSCodeNamespaces.workspace);
3335
});
3436

3537
test('Ensure command is registered with the correct callback handler', async () => {
@@ -68,6 +70,35 @@ suite('Interpreter Path Command', () => {
6870
expect(setting).to.equal('settingValue');
6971
});
7072

73+
test('If `args[1]` is missing but there is exactly one workspace folder, fall back to it (tasks.json case)', async () => {
74+
when(mockedVSCodeNamespaces.workspace!.workspaceFolders).thenReturn([
75+
{ uri: Uri.file('onlyFolderPath'), name: 'onlyFolder', index: 0 },
76+
]);
77+
78+
const args = ['command'];
79+
when(interpreterService.getActiveInterpreter(anything())).thenCall((arg) => {
80+
assert.deepEqual(arg, Uri.file('onlyFolderPath'));
81+
82+
return Promise.resolve({ path: 'settingValue' }) as unknown;
83+
});
84+
const setting = await interpreterPathCommand._getSelectedInterpreterPath(args);
85+
expect(setting).to.equal('settingValue');
86+
});
87+
88+
test('If `args[1]` is missing and there are multiple (or zero) workspace folders, value of workspace folder is `undefined`', async () => {
89+
when(mockedVSCodeNamespaces.workspace!.workspaceFolders).thenReturn([
90+
{ uri: Uri.file('folderOne'), name: 'folderOne', index: 0 },
91+
{ uri: Uri.file('folderTwo'), name: 'folderTwo', index: 1 },
92+
]);
93+
94+
const args = ['command'];
95+
when(interpreterService.getActiveInterpreter(undefined)).thenReturn(
96+
Promise.resolve({ path: 'settingValue' }) as Promise<PythonEnvironment | undefined>,
97+
);
98+
const setting = await interpreterPathCommand._getSelectedInterpreterPath(args);
99+
expect(setting).to.equal('settingValue');
100+
});
101+
71102
test('If interpreter path contains spaces, double quote it before returning', async () => {
72103
const args = ['command', 'folderPath'];
73104
when(interpreterService.getActiveInterpreter(anything())).thenCall((arg) => {

0 commit comments

Comments
 (0)