Skip to content

Commit bcac5c1

Browse files
author
Kartik Raj
authored
Use ${command:python.interpreterPath} to get selected interpreter path in launch.json and tasks.json (microsoft#11840)
* Added implementation * Replace config with command * Added migrations * Added tests * Added tests * Undo * News entry * Remove variable
1 parent 1c16780 commit bcac5c1

File tree

15 files changed

+176
-14
lines changed

15 files changed

+176
-14
lines changed

news/2 Fixes/11789.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use `${command:python.interpreterPath}` to get selected interpreter path in `launch.json` and `tasks.json`.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@
12121212
"pythonPath": {
12131213
"type": "string",
12141214
"description": "Path (fully qualified) to python executable. Defaults to the value in settings",
1215-
"default": "${config:python.interpreterPath}"
1215+
"default": "${command:python.interpreterPath}"
12161216
},
12171217
"args": {
12181218
"type": "array",
@@ -1350,7 +1350,7 @@
13501350
"pythonPath": {
13511351
"type": "string",
13521352
"description": "Path (fully qualified) to python executable. Defaults to the value in settings",
1353-
"default": "${config:python.interpreterPath}"
1353+
"default": "${command:python.interpreterPath}"
13541354
},
13551355
"stopOnEntry": {
13561356
"type": "boolean",

src/client/application/diagnostics/checks/invalidLaunchJsonDebugger.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ export class InvalidLaunchJsonDebuggerService extends BaseDiagnosticsService {
113113
if (fileContents.indexOf('"console": "none"') > 0) {
114114
diagnostics.push(new InvalidLaunchJsonDebuggerDiagnostic(DiagnosticCodes.ConsoleTypeDiagnostic, resource));
115115
}
116-
if (fileContents.indexOf('{config:python.pythonPath}') > 0) {
116+
if (
117+
fileContents.indexOf('{config:python.pythonPath}') > 0 ||
118+
fileContents.indexOf('{config:python.interpreterPath}') > 0
119+
) {
117120
diagnostics.push(
118121
new InvalidLaunchJsonDebuggerDiagnostic(DiagnosticCodes.ConfigPythonPathDiagnostic, resource, false)
119122
);
@@ -169,7 +172,12 @@ export class InvalidLaunchJsonDebuggerService extends BaseDiagnosticsService {
169172
fileContents = this.findAndReplace(
170173
fileContents,
171174
'{config:python.pythonPath}',
172-
'{config:python.interpreterPath}'
175+
'{command:python.interpreterPath}'
176+
);
177+
fileContents = this.findAndReplace(
178+
fileContents,
179+
'{config:python.interpreterPath}',
180+
'{command:python.interpreterPath}'
173181
);
174182
break;
175183
}

src/client/application/diagnostics/checks/invalidPythonPathInDebugger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class InvalidPythonPathInDebuggerService extends BaseDiagnosticsService
7676
public async validatePythonPath(pythonPath?: string, pythonPathSource?: PythonPathSource, resource?: Uri) {
7777
pythonPath = pythonPath ? this.resolveVariables(pythonPath, resource) : undefined;
7878
// tslint:disable-next-line:no-invalid-template-strings
79-
if (pythonPath === '${config:python.interpreterPath}' || !pythonPath) {
79+
if (pythonPath === '${command:python.interpreterPath}' || !pythonPath) {
8080
pythonPath = this.configService.getSettings(resource).pythonPath;
8181
}
8282
if (await this.interpreterHelper.getInterpreterInformation(pythonPath).catch(() => undefined)) {

src/client/common/application/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
9494
['vscode.open']: [Uri];
9595
['workbench.action.files.saveAs']: [Uri];
9696
['workbench.action.files.save']: [Uri];
97+
[Commands.GetSelectedInterpreterPath]: [{ workspaceFolder: string } | string[]];
9798
[Commands.Build_Workspace_Symbols]: [boolean, CancellationToken];
9899
[Commands.Sort_Imports]: [undefined, Uri];
99100
[Commands.Exec_In_Terminal]: [undefined, Uri];

src/client/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export namespace Commands {
6363
export const SwitchToInsidersDaily = 'python.switchToDailyChannel';
6464
export const SwitchToInsidersWeekly = 'python.switchToWeeklyChannel';
6565
export const PickLocalProcess = 'python.pickLocalProcess';
66+
export const GetSelectedInterpreterPath = 'python.interpreterPath';
6667
export const ClearWorkspaceInterpreter = 'python.clearWorkspaceInterpreter';
6768
export const ResetInterpreterSecurityStorage = 'python.resetInterpreterSecurityStorage';
6869
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
import { inject, injectable } from 'inversify';
7+
import { Uri } from 'vscode';
8+
import { IExtensionSingleActivationService } from '../../../../activation/types';
9+
import { ICommandManager } from '../../../../common/application/types';
10+
import { Commands } from '../../../../common/constants';
11+
import { IConfigurationService, IDisposable, IDisposableRegistry } from '../../../../common/types';
12+
13+
@injectable()
14+
export class InterpreterPathCommand implements IExtensionSingleActivationService {
15+
constructor(
16+
@inject(ICommandManager) private readonly commandManager: ICommandManager,
17+
@inject(IConfigurationService) private readonly configurationService: IConfigurationService,
18+
@inject(IDisposableRegistry) private readonly disposables: IDisposable[]
19+
) {}
20+
21+
public async activate() {
22+
this.disposables.push(
23+
this.commandManager.registerCommand(Commands.GetSelectedInterpreterPath, (args) => {
24+
return this._getSelectedInterpreterPath(args);
25+
})
26+
);
27+
}
28+
29+
public _getSelectedInterpreterPath(args: { workspaceFolder: string } | string[]): string {
30+
// If `launch.json` is launching this command, `args.workspaceFolder` carries the workspaceFolder
31+
// If `tasks.json` is launching this command, `args[1]` carries the workspaceFolder
32+
const workspaceFolder = 'workspaceFolder' in args ? args.workspaceFolder : args[1] ? args[1] : undefined;
33+
return this.configurationService.getSettings(workspaceFolder ? Uri.parse(workspaceFolder) : undefined)
34+
.pythonPath;
35+
}
36+
}

src/client/debugger/extension/configuration/resolvers/base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export abstract class BaseConfigurationResolver<T extends DebugConfiguration>
9191
if (!debugConfiguration) {
9292
return;
9393
}
94-
if (debugConfiguration.pythonPath === '${config:python.interpreterPath}' || !debugConfiguration.pythonPath) {
94+
if (debugConfiguration.pythonPath === '${command:python.interpreterPath}' || !debugConfiguration.pythonPath) {
9595
const pythonPath = this.configurationService.getSettings(workspaceFolder).pythonPath;
9696
debugConfiguration.pythonPath = pythonPath;
9797
this.pythonPathSource = PythonPathSource.settingsJson;

src/client/debugger/extension/serviceRegistry.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { IAttachProcessProviderFactory } from './attachQuickPick/types';
1515
import { DebuggerBanner } from './banner';
1616
import { PythonDebugConfigurationService } from './configuration/debugConfigurationService';
1717
import { LaunchJsonCompletionProvider } from './configuration/launch.json/completionProvider';
18+
import { InterpreterPathCommand } from './configuration/launch.json/interpreterPathCommand';
1819
import { LaunchJsonUpdaterService } from './configuration/launch.json/updaterService';
1920
import { DjangoLaunchDebugConfigurationProvider } from './configuration/providers/djangoLaunch';
2021
import { FileLaunchDebugConfigurationProvider } from './configuration/providers/fileLaunch';
@@ -51,6 +52,10 @@ export function registerTypes(serviceManager: IServiceManager) {
5152
IExtensionSingleActivationService,
5253
LaunchJsonCompletionProvider
5354
);
55+
serviceManager.addSingleton<IExtensionSingleActivationService>(
56+
IExtensionSingleActivationService,
57+
InterpreterPathCommand
58+
);
5459
serviceManager.addSingleton<IExtensionSingleActivationService>(
5560
IExtensionSingleActivationService,
5661
LaunchJsonUpdaterService

src/test/application/diagnostics/checks/invalidLaunchJsonDebugger.unit.test.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,31 @@ suite('Application Diagnostics - Checks if launch.json is invalid', () => {
218218
fs.verifyAll();
219219
});
220220

221+
test('Should return ConfigPythonPathDiagnostic if file launch.json contains string "{config:python.interpreterPath}"', async () => {
222+
const fileContents = 'Hello I am launch.json, I contain string {config:python.interpreterPath}';
223+
workspaceService
224+
.setup((w) => w.hasWorkspaceFolders)
225+
.returns(() => true)
226+
.verifiable(TypeMoq.Times.once());
227+
workspaceService
228+
.setup((w) => w.workspaceFolders)
229+
.returns(() => [workspaceFolder])
230+
.verifiable(TypeMoq.Times.once());
231+
fs.setup((w) => w.fileExists(TypeMoq.It.isAny()))
232+
.returns(() => Promise.resolve(true))
233+
.verifiable(TypeMoq.Times.once());
234+
fs.setup((w) => w.readFile(TypeMoq.It.isAny()))
235+
.returns(() => Promise.resolve(fileContents))
236+
.verifiable(TypeMoq.Times.once());
237+
const diagnostics = await diagnosticService.diagnose(undefined);
238+
expect(diagnostics).to.be.deep.equal(
239+
[new InvalidLaunchJsonDebuggerDiagnostic(DiagnosticCodes.ConfigPythonPathDiagnostic, undefined, false)],
240+
'Diagnostics returned are not as expected'
241+
);
242+
workspaceService.verifyAll();
243+
fs.verifyAll();
244+
});
245+
221246
test('Should return both diagnostics if file launch.json contains string "debugStdLib" and "pythonExperimental"', async () => {
222247
const fileContents = 'Hello I am launch.json, I contain both "debugStdLib" and "pythonExperimental"';
223248
workspaceService
@@ -471,8 +496,9 @@ suite('Application Diagnostics - Checks if launch.json is invalid', () => {
471496
});
472497

473498
test('File launch.json is fixed correctly when code equals ConfigPythonPathDiagnostic ', async () => {
474-
const launchJson = 'This string contains {config:python.pythonPath}';
475-
const correctedlaunchJson = 'This string contains {config:python.interpreterPath}';
499+
const launchJson = 'This string contains {config:python.pythonPath} & {config:python.interpreterPath}';
500+
const correctedlaunchJson =
501+
'This string contains {command:python.interpreterPath} & {command:python.interpreterPath}';
476502
workspaceService
477503
.setup((w) => w.hasWorkspaceFolders)
478504
.returns(() => true)

0 commit comments

Comments
 (0)