Skip to content

Commit b5f61b3

Browse files
author
Kartik Raj
committed
Merge branch 'main' of https://github.com/microsoft/vscode-python into envcollection
2 parents 7e21481 + b0ab10d commit b5f61b3

29 files changed

+348
-155
lines changed

gulpfile.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ async function addExtensionPackDependencies() {
8282
// extension dependencies need not be installed during development
8383
const packageJsonContents = await fsExtra.readFile('package.json', 'utf-8');
8484
const packageJson = JSON.parse(packageJsonContents);
85-
packageJson.extensionPack = ['ms-toolsai.jupyter', 'ms-python.vscode-pylance', 'ms-python.isort'].concat(
85+
packageJson.extensionPack = ['ms-toolsai.jupyter', 'ms-python.vscode-pylance'].concat(
8686
packageJson.extensionPack ? packageJson.extensionPack : [],
8787
);
8888
await fsExtra.writeFile('package.json', JSON.stringify(packageJson, null, 4), 'utf-8');

pythonFiles/sortImports.py

-14
This file was deleted.

src/client/activation/languageClientMiddlewareBase.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import {
1313
import { ConfigurationItem } from 'vscode-languageserver-protocol';
1414

1515
import { HiddenFilePrefix } from '../common/constants';
16-
import { IConfigurationService } from '../common/types';
1716
import { createDeferred, isThenable } from '../common/utils/async';
1817
import { StopWatch } from '../common/utils/stopWatch';
1918
import { IEnvironmentVariablesProvider } from '../common/variables/types';
19+
import { IInterpreterService } from '../interpreter/contracts';
2020
import { IServiceContainer } from '../ioc/types';
2121
import { EventName } from '../telemetry/constants';
2222
import { LanguageServerType } from './types';
@@ -66,7 +66,7 @@ export class LanguageClientMiddlewareBase implements Middleware {
6666
return next(params, token);
6767
}
6868

69-
const configService = this.serviceContainer.get<IConfigurationService>(IConfigurationService);
69+
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
7070
const envService = this.serviceContainer.get<IEnvironmentVariablesProvider>(IEnvironmentVariablesProvider);
7171

7272
let settings = next(params, token);
@@ -87,9 +87,10 @@ export class LanguageClientMiddlewareBase implements Middleware {
8787
const settingDict: LSPObject & { pythonPath: string; _envPYTHONPATH: string } = settings[
8888
i
8989
] as LSPObject & { pythonPath: string; _envPYTHONPATH: string };
90-
9190
settingDict.pythonPath =
92-
(await this.getPythonPathOverride(uri)) ?? configService.getSettings(uri).pythonPath;
91+
(await this.getPythonPathOverride(uri)) ??
92+
(await interpreterService.getActiveInterpreter(uri))?.path ??
93+
'python';
9394

9495
const env = await envService.getEnvironmentVariables(uri);
9596
const envPYTHONPATH = env.PYTHONPATH;

src/client/common/process/internal/scripts/index.ts

-17
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,6 @@ export function interpreterInfo(): [string[], (out: string) => InterpreterInfoJs
5858
return [args, parse];
5959
}
6060

61-
// sortImports.py
62-
63-
export function sortImports(filename: string, sortArgs?: string[]): [string[], (out: string) => string] {
64-
const script = path.join(SCRIPTS_DIR, 'sortImports.py');
65-
const args = [script, filename, '--diff'];
66-
if (sortArgs) {
67-
args.push(...sortArgs);
68-
}
69-
70-
function parse(out: string) {
71-
// It should just be a diff that the extension will use directly.
72-
return out;
73-
}
74-
75-
return [args, parse];
76-
}
77-
7861
// normalizeSelection.py
7962

8063
export function normalizeSelection(): [string[], (out: string) => string] {

src/client/common/utils/localize.ts

+4
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,10 @@ export namespace ToolsExtensions {
467467
export const pylintPromptMessage = l10n.t(
468468
'Use the Pylint extension to enable easier configuration and new features such as quick fixes.',
469469
);
470+
export const isortPromptMessage = l10n.t(
471+
'To use sort imports, please install the isort extension. It provides easier configuration and new features such as code actions.',
472+
);
470473
export const installPylintExtension = l10n.t('Install Pylint extension');
471474
export const installFlake8Extension = l10n.t('Install Flake8 extension');
475+
export const installISortExtension = l10n.t('Install isort extension');
472476
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import * as path from 'path';
5+
import * as fs from 'fs-extra';
6+
import { Extension, extensions } from 'vscode';
7+
import { PVSC_EXTENSION_ID } from '../constants';
8+
9+
export function getExtension<T = unknown>(extensionId: string): Extension<T> | undefined {
10+
return extensions.getExtension(extensionId);
11+
}
12+
13+
export function isExtensionEnabled(extensionId: string): boolean {
14+
return extensions.getExtension(extensionId) !== undefined;
15+
}
16+
17+
export function isExtensionDisabled(extensionId: string): boolean {
18+
// We need an enabled extension to find the extensions dir.
19+
const pythonExt = getExtension(PVSC_EXTENSION_ID);
20+
if (pythonExt) {
21+
let found = false;
22+
fs.readdirSync(path.dirname(pythonExt.extensionPath), { withFileTypes: false }).forEach((s) => {
23+
if (s.toString().startsWith(extensionId)) {
24+
found = true;
25+
}
26+
});
27+
return found;
28+
}
29+
return false;
30+
}

src/client/interpreter/configuration/pythonPathUpdaterService.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { inject, injectable } from 'inversify';
2-
import * as path from 'path';
32
import { ConfigurationTarget, l10n, Uri, window } from 'vscode';
43
import { StopWatch } from '../../common/utils/stopWatch';
54
import { SystemVariables } from '../../common/variables/systemVariables';
@@ -28,7 +27,7 @@ export class PythonPathUpdaterService implements IPythonPathUpdaterServiceManage
2827
const pythonPathUpdater = this.getPythonUpdaterService(configTarget, wkspace);
2928
let failed = false;
3029
try {
31-
await pythonPathUpdater.updatePythonPath(pythonPath ? path.normalize(pythonPath) : undefined);
30+
await pythonPathUpdater.updatePythonPath(pythonPath);
3231
} catch (err) {
3332
failed = true;
3433
const reason = err as Error;

src/client/interpreter/configuration/services/workspaceFolderUpdaterService.ts

-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as path from 'path';
21
import { ConfigurationTarget, Uri } from 'vscode';
32
import { IInterpreterPathService } from '../../../common/types';
43
import { IPythonPathUpdaterService } from '../types';
@@ -11,9 +10,6 @@ export class WorkspaceFolderPythonPathUpdaterService implements IPythonPathUpdat
1110
if (pythonPathValue && pythonPathValue.workspaceFolderValue === pythonPath) {
1211
return;
1312
}
14-
if (pythonPath && pythonPath.startsWith(this.workspaceFolder.fsPath)) {
15-
pythonPath = path.relative(this.workspaceFolder.fsPath, pythonPath);
16-
}
1713
await this.interpreterPathService.update(this.workspaceFolder, ConfigurationTarget.WorkspaceFolder, pythonPath);
1814
}
1915
}

src/client/interpreter/configuration/services/workspaceUpdaterService.ts

-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as path from 'path';
21
import { ConfigurationTarget, Uri } from 'vscode';
32
import { IInterpreterPathService } from '../../../common/types';
43
import { IPythonPathUpdaterService } from '../types';
@@ -11,9 +10,6 @@ export class WorkspacePythonPathUpdaterService implements IPythonPathUpdaterServ
1110
if (pythonPathValue && pythonPathValue.workspaceValue === pythonPath) {
1211
return;
1312
}
14-
if (pythonPath && pythonPath.startsWith(this.workspace.fsPath)) {
15-
pythonPath = path.relative(this.workspace.fsPath, pythonPath);
16-
}
1713
await this.interpreterPathService.update(this.workspace, ConfigurationTarget.Workspace, pythonPath);
1814
}
1915
}

src/client/interpreter/interpreterService.ts

+21-21
Original file line numberDiff line numberDiff line change
@@ -186,28 +186,28 @@ export class InterpreterService implements Disposable, IInterpreterService {
186186
// However we need not wait on the update to take place, as we can use the value directly.
187187
if (!path) {
188188
path = this.configService.getSettings(resource).pythonPath;
189-
}
190-
if (pathUtils.basename(path) === path) {
191-
// Value can be `python`, `python3`, `python3.9` etc.
192-
// Note the following triggers autoselection if no interpreter is explictly
193-
// selected, i.e the value is `python`.
194-
// During shutdown we might not be able to get items out of the service container.
195-
const pythonExecutionFactory = this.serviceContainer.tryGet<IPythonExecutionFactory>(
196-
IPythonExecutionFactory,
197-
);
198-
const pythonExecutionService = pythonExecutionFactory
199-
? await pythonExecutionFactory.create({ resource })
200-
: undefined;
201-
const fullyQualifiedPath = pythonExecutionService
202-
? await pythonExecutionService.getExecutablePath().catch((ex) => {
203-
traceError(ex);
204-
})
205-
: undefined;
206-
// Python path is invalid or python isn't installed.
207-
if (!fullyQualifiedPath) {
208-
return undefined;
189+
if (pathUtils.basename(path) === path) {
190+
// Value can be `python`, `python3`, `python3.9` etc.
191+
// Note the following triggers autoselection if no interpreter is explictly
192+
// selected, i.e the value is `python`.
193+
// During shutdown we might not be able to get items out of the service container.
194+
const pythonExecutionFactory = this.serviceContainer.tryGet<IPythonExecutionFactory>(
195+
IPythonExecutionFactory,
196+
);
197+
const pythonExecutionService = pythonExecutionFactory
198+
? await pythonExecutionFactory.create({ resource })
199+
: undefined;
200+
const fullyQualifiedPath = pythonExecutionService
201+
? await pythonExecutionService.getExecutablePath().catch((ex) => {
202+
traceError(ex);
203+
})
204+
: undefined;
205+
// Python path is invalid or python isn't installed.
206+
if (!fullyQualifiedPath) {
207+
return undefined;
208+
}
209+
path = fullyQualifiedPath;
209210
}
210-
path = fullyQualifiedPath;
211211
}
212212
return this.getInterpreterDetails(path);
213213
}

src/client/interpreter/virtualEnvs/activatedEnvLaunch.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { IProcessServiceFactory } from '../../common/process/types';
99
import { sleep } from '../../common/utils/async';
1010
import { cache } from '../../common/utils/decorators';
1111
import { Common, Interpreters } from '../../common/utils/localize';
12-
import { traceError, traceLog, traceWarn } from '../../logging';
12+
import { traceError, traceLog, traceVerbose, traceWarn } from '../../logging';
1313
import { Conda } from '../../pythonEnvironments/common/environmentManagers/conda';
1414
import { sendTelemetryEvent } from '../../telemetry';
1515
import { EventName } from '../../telemetry/constants';
@@ -89,6 +89,11 @@ export class ActivatedEnvironmentLaunch implements IActivatedEnvironmentLaunch {
8989
// Assuming multiroot workspaces cannot be directly launched via `code .` command.
9090
return undefined;
9191
}
92+
if (process.env.VSCODE_CLI !== '1') {
93+
// We only want to select the interpreter if VS Code was launched from the command line.
94+
traceVerbose('VS Code was not launched from the command line, not selecting activated interpreter');
95+
return undefined;
96+
}
9297
const prefix = await this.getPrefixOfSelectedActivatedEnv();
9398
if (!prefix) {
9499
this._promptIfApplicable().ignoreErrors();

src/client/linters/flake8.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { Product } from '../common/types';
44
import { IServiceContainer } from '../ioc/types';
55
import { traceLog } from '../logging';
66
import { BaseLinter } from './baseLinter';
7+
import { isExtensionEnabled } from './prompts/common';
8+
import { FLAKE8_EXTENSION } from './prompts/flake8Prompt';
79
import { IToolsExtensionPrompt } from './prompts/types';
810
import { ILintMessage } from './types';
911

@@ -15,8 +17,12 @@ export class Flake8 extends BaseLinter {
1517
}
1618

1719
protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise<ILintMessage[]> {
18-
if (await this.prompt.showPrompt()) {
19-
traceLog('LINTING: Skipping linting from Python extension, since Flake8 extension is installed.');
20+
await this.prompt.showPrompt();
21+
22+
if (isExtensionEnabled(this.serviceContainer, FLAKE8_EXTENSION)) {
23+
traceLog(
24+
'LINTING: Skipping linting from Python extension, since Flake8 extension is installed and enabled.',
25+
);
2026
return [];
2127
}
2228

src/client/linters/prompts/common.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { IExperimentService, IExtensions, IPersistentState, IPersistentStateFact
88
import { IServiceContainer } from '../../ioc/types';
99
import { traceLog } from '../../logging';
1010

11-
function isExtensionInstalledButDisabled(extensions: IExtensions, extensionId: string): boolean {
11+
export function isExtensionDisabled(serviceContainer: IServiceContainer, extensionId: string): boolean {
12+
const extensions: IExtensions = serviceContainer.get<IExtensions>(IExtensions);
1213
// When debugging the python extension this `extensionPath` below will point to your repo.
1314
// If you are debugging this feature then set the `extensionPath` to right location after
1415
// the next line.
@@ -26,13 +27,12 @@ function isExtensionInstalledButDisabled(extensions: IExtensions, extensionId: s
2627
return false;
2728
}
2829

29-
export function isExtensionInstalled(serviceContainer: IServiceContainer, extensionId: string): boolean {
30+
/**
31+
* Detects if extension is installed and enabled.
32+
*/
33+
export function isExtensionEnabled(serviceContainer: IServiceContainer, extensionId: string): boolean {
3034
const extensions: IExtensions = serviceContainer.get<IExtensions>(IExtensions);
3135
const extension = extensions.getExtension(extensionId);
32-
if (!extension) {
33-
// The extension you are looking for might be disabled.
34-
return isExtensionInstalledButDisabled(extensions, extensionId);
35-
}
3636
return extension !== undefined;
3737
}
3838

src/client/linters/prompts/flake8Prompt.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { showInformationMessage } from '../../common/vscodeApis/windowApis';
88
import { IServiceContainer } from '../../ioc/types';
99
import { sendTelemetryEvent } from '../../telemetry';
1010
import { EventName } from '../../telemetry/constants';
11-
import { isExtensionInstalled, doNotShowPromptState, inToolsExtensionsExperiment } from './common';
11+
import { doNotShowPromptState, inToolsExtensionsExperiment, isExtensionDisabled, isExtensionEnabled } from './common';
1212
import { IToolsExtensionPrompt } from './types';
1313

1414
export const FLAKE8_EXTENSION = 'ms-python.flake8';
@@ -20,9 +20,11 @@ export class Flake8ExtensionPrompt implements IToolsExtensionPrompt {
2020
public constructor(private readonly serviceContainer: IServiceContainer) {}
2121

2222
public async showPrompt(): Promise<boolean> {
23-
if (isExtensionInstalled(this.serviceContainer, FLAKE8_EXTENSION)) {
23+
const isEnabled = isExtensionEnabled(this.serviceContainer, FLAKE8_EXTENSION);
24+
if (isEnabled || isExtensionDisabled(this.serviceContainer, FLAKE8_EXTENSION)) {
2425
sendTelemetryEvent(EventName.TOOLS_EXTENSIONS_ALREADY_INSTALLED, undefined, {
2526
extensionId: FLAKE8_EXTENSION,
27+
isEnabled,
2628
});
2729
return true;
2830
}

src/client/linters/prompts/pylintPrompt.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { showInformationMessage } from '../../common/vscodeApis/windowApis';
88
import { IServiceContainer } from '../../ioc/types';
99
import { sendTelemetryEvent } from '../../telemetry';
1010
import { EventName } from '../../telemetry/constants';
11-
import { doNotShowPromptState, inToolsExtensionsExperiment, isExtensionInstalled } from './common';
11+
import { doNotShowPromptState, inToolsExtensionsExperiment, isExtensionDisabled, isExtensionEnabled } from './common';
1212
import { IToolsExtensionPrompt } from './types';
1313

1414
export const PYLINT_EXTENSION = 'ms-python.pylint';
@@ -20,9 +20,11 @@ export class PylintExtensionPrompt implements IToolsExtensionPrompt {
2020
public constructor(private readonly serviceContainer: IServiceContainer) {}
2121

2222
public async showPrompt(): Promise<boolean> {
23-
if (isExtensionInstalled(this.serviceContainer, PYLINT_EXTENSION)) {
23+
const isEnabled = isExtensionEnabled(this.serviceContainer, PYLINT_EXTENSION);
24+
if (isEnabled || isExtensionDisabled(this.serviceContainer, PYLINT_EXTENSION)) {
2425
sendTelemetryEvent(EventName.TOOLS_EXTENSIONS_ALREADY_INSTALLED, undefined, {
2526
extensionId: PYLINT_EXTENSION,
27+
isEnabled,
2628
});
2729
return true;
2830
}

src/client/linters/pylint.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { Product } from '../common/types';
77
import { IServiceContainer } from '../ioc/types';
88
import { traceError, traceLog } from '../logging';
99
import { BaseLinter } from './baseLinter';
10+
import { isExtensionEnabled } from './prompts/common';
11+
import { PYLINT_EXTENSION } from './prompts/pylintPrompt';
1012
import { IToolsExtensionPrompt } from './prompts/types';
1113
import { ILintMessage } from './types';
1214

@@ -26,8 +28,12 @@ export class Pylint extends BaseLinter {
2628
}
2729

2830
protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise<ILintMessage[]> {
29-
if (await this.prompt.showPrompt()) {
30-
traceLog('LINTING: Skipping linting from Python extension, since Pylint extension is installed.');
31+
await this.prompt.showPrompt();
32+
33+
if (isExtensionEnabled(this.serviceContainer, PYLINT_EXTENSION)) {
34+
traceLog(
35+
'LINTING: Skipping linting from Python extension, since Pylint extension is installed and enabled.',
36+
);
3137
return [];
3238
}
3339

0 commit comments

Comments
 (0)