Skip to content

Implements linting configuration #599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 83 commits into from
Jan 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
7675901
Basic tokenizer
Dec 1, 2017
eb42669
Fixed property names
Dec 1, 2017
2756974
Tests, round I
Dec 1, 2017
c2c1ced
Tests, round II
Dec 2, 2017
a108c96
merge master
Dec 3, 2017
14864a5
tokenizer test
Dec 4, 2017
0ed51d6
Remove temorary change
Dec 4, 2017
51b544c
Fix merge issue
Dec 4, 2017
3cd11e6
Merge conflict
Dec 4, 2017
82e0ad1
Merge conflict
Dec 4, 2017
9295c1a
Completion test
Dec 4, 2017
06eb1a5
Fix last line
Dec 4, 2017
e9db8e0
Fix javascript math
Dec 4, 2017
d12ca03
Merge master
Dec 5, 2017
d8ab041
Make test await for results
Dec 5, 2017
db75cd0
Add license headers
Dec 5, 2017
9ab2c47
Rename definitions to types
Dec 5, 2017
d587485
License headers
Dec 5, 2017
1da5e0a
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Dec 5, 2017
7668cee
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Dec 11, 2017
1ac4932
Fix typo in completion details (typo)
Dec 11, 2017
2aa5a6c
Fix hover test
Dec 12, 2017
5db31bd
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Dec 12, 2017
560d2af
Russian translations
Dec 13, 2017
c71024d
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Dec 13, 2017
31aa087
Update to better translation
Dec 13, 2017
593ae05
Fix typo
Dec 13, 2017
e6d69bb
#70 How to get all parameter info when filling in a function param list
Dec 13, 2017
b5a23d3
Fix #70 How to get all parameter info when filling in a function para…
Dec 14, 2017
cd200f7
Clean up
Dec 14, 2017
7c33228
Clean imports
Dec 14, 2017
c4a6b90
CR feedback
Dec 14, 2017
f85b848
Trim whitespace for test stability
Dec 14, 2017
37c210b
More tests
Dec 15, 2017
61a5650
Better handle no-parameters documentation
Dec 15, 2017
a10305e
Better handle ellipsis and Python3
Dec 15, 2017
bfcae78
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Dec 15, 2017
42a5f79
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Dec 18, 2017
e4ba322
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Jan 8, 2018
7baec1a
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Jan 9, 2018
9cb43e7
#385 Auto-Indentation doesn't work after comment
Jan 9, 2018
5a9c3fd
#141 Auto indentation broken when return keyword involved
Jan 9, 2018
9800c4a
Undo changes
Jan 9, 2018
3205d33
Merge branch 'master' of https://github.com/Microsoft/vscode-python
Jan 11, 2018
de6a59c
Round I
Jan 11, 2018
c374a43
Round 2
Jan 12, 2018
d1f429b
Round 3
Jan 12, 2018
7eca943
Round 4
Jan 13, 2018
595f63c
Round 5
Jan 16, 2018
86e3e05
no message
Jan 16, 2018
c02bd84
Round 6
Jan 17, 2018
c15fdb2
Round 7
Jan 18, 2018
29833eb
Clean up targets and messages
Jan 18, 2018
5c729db
Settings propagation
Jan 18, 2018
a5aa108
Tests
Jan 18, 2018
7848d1b
Test warning
Jan 18, 2018
2da60af
Fix installer tests
Jan 18, 2018
372c855
Tests
Jan 18, 2018
3800516
Merge branch 'master' of https://github.com/Microsoft/vscode-python i…
Jan 18, 2018
d3afee8
Merge branch 'master' of https://github.com/Microsoft/vscode-python i…
Jan 19, 2018
2f361f5
Test fixes
Jan 19, 2018
384ca3a
Fix terminal service and tests async/await
Jan 19, 2018
4dc23fb
Fix mock setup
Jan 19, 2018
82e4d52
Test fix
Jan 19, 2018
8207953
Test async/await fix
Jan 19, 2018
8b701d2
Test fix + activate tslint on awaits
Jan 19, 2018
c5ece0a
Use command manager
Jan 19, 2018
5972c11
Work around updateSettings
Jan 19, 2018
11a4891
Multiroot fixes, partial
Jan 20, 2018
84562bf
More workarounds
Jan 20, 2018
b5c547a
Multiroot tests
Jan 21, 2018
ecb90a6
Fix installer test
Jan 21, 2018
cd79d03
Test fixes
Jan 21, 2018
27a4244
Disable prospector
Jan 22, 2018
34365a5
Enable dispose in all cases
Jan 22, 2018
9071ea8
Fix event firing
Jan 22, 2018
4e2c620
Min pylint options
Jan 22, 2018
c090581
Min checkers & pylintrc discovery
Jan 23, 2018
96fcba1
Fix Windows path in tests for Travis
Jan 23, 2018
25c7d0a
Fix Mac test
Jan 23, 2018
c824c3e
Merge branch 'master' of https://github.com/Microsoft/vscode-python i…
Jan 24, 2018
9de1d81
Merge branch 'lint' of https://github.com/MikhailArkhipov/vscode-pyth…
Jan 24, 2018
36e2fa9
Test fix
Jan 24, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6,322 changes: 6,322 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

26 changes: 19 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@
"onCommand:python.buildWorkspaceSymbols",
"onCommand:python.updateSparkLibrary",
"onCommand:python.startREPL",
"onCommand:python.goToPythonObject"
"onCommand:python.goToPythonObject",
"onCommand:python.setLinter",
"onCommand:python.enableLinting"
],
"main": "./out/client/extension",
"contributes": {
Expand Down Expand Up @@ -213,6 +215,16 @@
"command": "python.goToPythonObject",
"title": "%python.command.python.goToPythonObject.title%",
"category": "Python"
},
{
"command": "python.setLinter",
"title": "%python.command.python.setLinter.title%",
"category": "Python"
},
{
"command": "python.enableLinting",
"title": "%python.command.python.enableLinting.title%",
"category": "Python"
}
],
"menus": {
Expand Down Expand Up @@ -949,12 +961,6 @@
"description": "Whether to lint Python files.",
"scope": "resource"
},
"python.linting.enabledWithoutWorkspace": {
"type": "boolean",
"default": true,
"description": "Whether to lint Python files when no workspace is opened.",
"scope": "resource"
},
"python.linting.prospectorEnabled": {
"type": "boolean",
"default": false,
Expand Down Expand Up @@ -1003,6 +1009,12 @@
"description": "Controls the maximum number of problems produced by the server.",
"scope": "resource"
},
"python.linting.pylintUseMinimalCheckers": {
"type": "boolean",
"default": true,
"description": "Whether to run Pylint with minimal set of rules.",
"scope": "resource"
},
"python.linting.pylintCategorySeverity.convention": {
"type": "string",
"default": "Information",
Expand Down
2 changes: 2 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"python.command.jupyter.gotToPreviousCell.title": "Go to Previous Cell",
"python.command.jupyter.gotToNextCell.title": "Go to Next Cell",
"python.command.python.goToPythonObject.title": "Go to Python Object",
"python.command.python.setLinter.title": "Select Linter",
"python.command.python.enableLinting.title": "Enable Linting",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use this command to disable linting as well?
Three buttons, last being the default VS Code button.
E.g. Enable or disable linting [Enable Linting] [Disable Linting] [Close]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It currently shows on/off list

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

"python.snippet.launch.standard.label": "Python",
"python.snippet.launch.standard.description": "Debug a Python program with standard output",
"python.snippet.launch.pyspark.label": "Python: PySpark",
Expand Down
2 changes: 2 additions & 0 deletions package.nls.ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"python.command.jupyter.gotToPreviousCell.title": "Перейти к предыдущей ячейке",
"python.command.jupyter.gotToNextCell.title": "Перейти к следующей ячейке",
"python.command.python.goToPythonObject.title": "Перейти к объекту Python",
"python.command.python.setLinter.title": "Выбрать анализатор кода",
"python.command.python.enableLinting.title": "Включить анализатор кода",
"python.snippet.launch.standard.label": "Python",
"python.snippet.launch.standard.description": "Отладить программу Python со стандартным выводом",
"python.snippet.launch.pyspark.label": "Python: PySpark",
Expand Down
26 changes: 18 additions & 8 deletions src/client/common/configSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as child_process from 'child_process';
import { EventEmitter } from 'events';
import * as path from 'path';
import * as vscode from 'vscode';
import { Uri } from 'vscode';
import { ConfigurationTarget, Uri } from 'vscode';
import {
IAutoCompeteSettings,
IFormattingSettings,
Expand Down Expand Up @@ -61,19 +61,29 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
}
// tslint:disable-next-line:function-name
public static getInstance(resource?: Uri): PythonSettings {
const workspaceFolder = resource ? vscode.workspace.getWorkspaceFolder(resource) : undefined;
let workspaceFolderUri: Uri | undefined = workspaceFolder ? workspaceFolder.uri : undefined;
if (!workspaceFolderUri && Array.isArray(vscode.workspace.workspaceFolders) && vscode.workspace.workspaceFolders.length > 0) {
workspaceFolderUri = vscode.workspace.workspaceFolders[0].uri;
}
const workspaceFolderUri = PythonSettings.getSettingsUriAndTarget(resource).uri;
const workspaceFolderKey = workspaceFolderUri ? workspaceFolderUri.fsPath : '';

if (!PythonSettings.pythonSettings.has(workspaceFolderKey)) {
const settings = new PythonSettings(workspaceFolderUri);
PythonSettings.pythonSettings.set(workspaceFolderKey, settings);
}
// tslint:disable-next-line:no-non-null-assertion
return PythonSettings.pythonSettings.get(workspaceFolderKey)!;
}

public static getSettingsUriAndTarget(resource?: Uri): { uri: Uri | undefined, target: ConfigurationTarget } {
const workspaceFolder = resource ? vscode.workspace.getWorkspaceFolder(resource) : undefined;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use IWorkspaceService instead of the vscode.workspace namespace. You should be able to mock the settings this way and be able to remove test specific code from the extension as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I prefer to use actual objects where possible since they work same way in tests as they do at run time. Mocking is more for something that cannot be instantiated easily for whatever reason (ex project system in big VS) or simulate things that are hard to change (such as registry data - which requires Windows and admin rights).

let workspaceFolderUri: Uri | undefined = workspaceFolder ? workspaceFolder.uri : undefined;

if (!workspaceFolderUri && Array.isArray(vscode.workspace.workspaceFolders) && vscode.workspace.workspaceFolders.length > 0) {
workspaceFolderUri = vscode.workspace.workspaceFolders[0].uri;
}

const target = workspaceFolderUri ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Global;
return { uri: workspaceFolderUri, target };
}

// tslint:disable-next-line:function-name
public static dispose() {
if (!isTestExecution()) {
Expand Down Expand Up @@ -138,7 +148,6 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
// Support for travis.
this.linting = this.linting ? this.linting : {
enabled: false,
enabledWithoutWorkspace: false,
ignorePatterns: [],
flake8Args: [], flake8Enabled: false, flake8Path: 'flake',
lintOnSave: false, maxNumberOfProblems: 100,
Expand Down Expand Up @@ -167,7 +176,8 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
mypyCategorySeverity: {
error: vscode.DiagnosticSeverity.Error,
note: vscode.DiagnosticSeverity.Hint
}
},
pylintUseMinimalCheckers: false
};
this.linting.pylintPath = getAbsolutePath(systemVariables.resolveAny(this.linting.pylintPath), workspaceRoot);
this.linting.flake8Path = getAbsolutePath(systemVariables.resolveAny(this.linting.flake8Path), workspaceRoot);
Expand Down
46 changes: 45 additions & 1 deletion src/client/common/configuration/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

import { injectable } from 'inversify';
import { Uri } from 'vscode';
import { ConfigurationTarget, Uri, workspace, WorkspaceConfiguration } from 'vscode';
import { PythonSettings } from '../configSettings';
import { IConfigurationService, IPythonSettings } from '../types';

Expand All @@ -11,4 +11,48 @@ export class ConfigurationService implements IConfigurationService {
public getSettings(resource?: Uri): IPythonSettings {
return PythonSettings.getInstance(resource);
}
public async updateSettingAsync(setting: string, value?: {}, resource?: Uri, configTarget?: ConfigurationTarget): Promise<void> {
const settingsInfo = PythonSettings.getSettingsUriAndTarget(resource);

const pythonConfig = workspace.getConfiguration('python', settingsInfo.uri);
const currentValue = pythonConfig.inspect(setting);

if (currentValue !== undefined &&
((settingsInfo.target === ConfigurationTarget.Global && currentValue.globalValue === value) ||
(settingsInfo.target === ConfigurationTarget.Workspace && currentValue.workspaceValue === value) ||
(settingsInfo.target === ConfigurationTarget.WorkspaceFolder && currentValue.workspaceFolderValue === value))) {
return;
}

await pythonConfig.update(setting, value, settingsInfo.target);
await this.verifySetting(pythonConfig, settingsInfo.target, setting, value);
}

public isTestExecution(): boolean {
return process.env.VSC_PYTHON_CI_TEST === '1';
}

private async verifySetting(pythonConfig: WorkspaceConfiguration, target: ConfigurationTarget, settingName: string, value?: {}): Promise<void> {
if (this.isTestExecution()) {
let retries = 0;
do {
const setting = pythonConfig.inspect(settingName);
if (!setting && value === undefined) {
break; // Both are unset
}
if (setting && value !== undefined) {
// Both specified
const actual = target === ConfigurationTarget.Global
? setting.globalValue
: target === ConfigurationTarget.Workspace ? setting.workspaceValue : setting.workspaceFolderValue;
if (actual === value) {
break;
}
}
// Wait for settings to get refreshed.
await new Promise((resolve, reject) => setTimeout(resolve, 250));
retries += 1;
} while (retries < 20);
}
}
}
3 changes: 3 additions & 0 deletions src/client/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const PythonLanguage = { language: 'python' };

export namespace Commands {
export const Set_Interpreter = 'python.setInterpreter';
export const Set_ShebangInterpreter = 'python.setShebangInterpreter';
export const Exec_In_Terminal = 'python.execInTerminal';
export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal';
export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell';
Expand All @@ -27,6 +28,8 @@ export namespace Commands {
export const Update_SparkLibrary = 'python.updateSparkLibrary';
export const Build_Workspace_Symbols = 'python.buildWorkspaceSymbols';
export const Start_REPL = 'python.startREPL';
export const Set_Linter = 'python.setLinter';
export const Enable_Linter = 'python.enableLinting';
}
export namespace Octicons {
export const Test_Pass = '$(check)';
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/errors/moduleNotInstalledError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

export class ModuleNotInstalledError extends Error {
constructor(moduleName: string) {
super(`Module '${moduleName} not installed.`);
super(`Module '${moduleName}' not installed.`);
}
}
61 changes: 3 additions & 58 deletions src/client/common/installer/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ConfigurationTarget, QuickPickItem, Uri, window, workspace } from 'vsco
import * as vscode from 'vscode';
import { IFormatterHelper } from '../../formatters/types';
import { IServiceContainer } from '../../ioc/types';
import { ILinterHelper } from '../../linters/types';
import { ILinterManager } from '../../linters/types';
import { ITestsHelper } from '../../unittests/common/types';
import { PythonSettings } from '../configSettings';
import { STANDARD_OUTPUT_CHANNEL } from '../constants';
Expand Down Expand Up @@ -34,17 +34,6 @@ ProductNames.set(Product.pytest, 'pytest');
ProductNames.set(Product.yapf, 'yapf');
ProductNames.set(Product.rope, 'rope');

export const SettingToDisableProduct = new Map<Product, string>();
SettingToDisableProduct.set(Product.flake8, 'linting.flake8Enabled');
SettingToDisableProduct.set(Product.mypy, 'linting.mypyEnabled');
SettingToDisableProduct.set(Product.nosetest, 'unitTest.nosetestsEnabled');
SettingToDisableProduct.set(Product.pep8, 'linting.pep8Enabled');
SettingToDisableProduct.set(Product.pylama, 'linting.pylamaEnabled');
SettingToDisableProduct.set(Product.prospector, 'linting.prospectorEnabled');
SettingToDisableProduct.set(Product.pydocstyle, 'linting.pydocstyleEnabled');
SettingToDisableProduct.set(Product.pylint, 'linting.pylintEnabled');
SettingToDisableProduct.set(Product.pytest, 'unitTest.pyTestEnabled');

// tslint:disable-next-line:variable-name
const ProductInstallationPrompt = new Map<Product, string>();
ProductInstallationPrompt.set(Product.ctags, 'Install CTags to enable Python workspace symbols');
Expand Down Expand Up @@ -92,25 +81,14 @@ export class Installer implements IInstaller {
const productTypeName = ProductTypeNames.get(productType)!;
const productName = ProductNames.get(product)!;

if (!this.shouldDisplayPrompt(product)) {
const message = `${productTypeName} '${productName}' not installed.`;
this.outputChannel.appendLine(message);
return InstallerResponse.Ignore;
}

const installOption = ProductInstallationPrompt.has(product) ? ProductInstallationPrompt.get(product)! : `Install ${productName}`;
const disableOption = `Disable ${productTypeName}`;
const dontShowAgain = 'Don\'t show this prompt again';
const alternateFormatter = product === Product.autopep8 ? 'yapf' : 'autopep8';
const useOtherFormatter = `Use '${alternateFormatter}' formatter`;
const options: string[] = [];
options.push(installOption);
if (productType === ProductType.Formatter) {
options.push(...[useOtherFormatter]);
}
if (SettingToDisableProduct.has(product)) {
options.push(...[disableOption, dontShowAgain]);
}
const item = await window.showErrorMessage(`${productTypeName} ${productName} is not installed`, ...options);
if (!item) {
return InstallerResponse.Ignore;
Expand All @@ -119,24 +97,10 @@ export class Installer implements IInstaller {
case installOption: {
return this.install(product, resource);
}
case disableOption: {
if (ProductTypes.has(product) && ProductTypes.get(product)! === ProductType.Linter) {
return this.disableLinter(product, resource).then(() => InstallerResponse.Disabled);
} else {
const settingToDisable = SettingToDisableProduct.get(product)!;
return this.updateSetting(settingToDisable, false, resource).then(() => InstallerResponse.Disabled);
}
}
case useOtherFormatter: {
return this.updateSetting('formatting.provider', alternateFormatter, resource)
.then(() => InstallerResponse.Installed);
}
case dontShowAgain: {
const pythonConfig = workspace.getConfiguration('python');
const features = pythonConfig.get('disablePromptForFeatures', [] as string[]);
features.push(productName);
return pythonConfig.update('disablePromptForFeatures', features, true).then(() => InstallerResponse.Ignore);
}
default: {
throw new Error('Invalid selection');
}
Expand Down Expand Up @@ -210,24 +174,6 @@ export class Installer implements IInstaller {
.catch(() => false);
}
}
public async disableLinter(product: Product, resource?: Uri) {
if (resource && workspace.getWorkspaceFolder(resource)) {
const settingToDisable = SettingToDisableProduct.get(product)!;
const pythonConfig = workspace.getConfiguration('python', resource);
const isMultiroot = Array.isArray(workspace.workspaceFolders) && workspace.workspaceFolders.length > 1;
const configTarget = isMultiroot ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace;
return pythonConfig.update(settingToDisable, false, configTarget);
} else {
const pythonConfig = workspace.getConfiguration('python');
return pythonConfig.update('linting.enabledWithoutWorkspace', false, true);
}
}
private shouldDisplayPrompt(product: Product) {
const productName = ProductNames.get(product)!;
const pythonConfig = workspace.getConfiguration('python');
const disablePromptForFeatures = pythonConfig.get('disablePromptForFeatures', [] as string[]);
return disablePromptForFeatures.indexOf(productName) === -1;
}
private installCTags() {
if (this.serviceContainer.get<IPlatformService>(IPlatformService).isWindows) {
this.outputChannel.appendLine('Install Universal Ctags Win32 to enable support for Workspace Symbols');
Expand Down Expand Up @@ -302,9 +248,8 @@ export class Installer implements IInstaller {
}
case ProductType.RefactoringLibrary: return this.translateProductToModuleName(product, ModuleNamePurpose.run);
case ProductType.Linter: {
const linterHelper = this.serviceContainer.get<ILinterHelper>(ILinterHelper);
const settingsPropNames = linterHelper.getSettingsPropertyNames(product);
return settings.linting[settingsPropNames.pathName] as string;
const linterManager = this.serviceContainer.get<ILinterManager>(ILinterManager);
return linterManager.getLinterInfo(product).pathName(resource);
}
default: {
throw new Error(`Unrecognized Product '${product}'`);
Expand Down
8 changes: 2 additions & 6 deletions src/client/common/installer/pipInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@ import { IModuleInstaller } from './types';

@injectable()
export class PipInstaller extends ModuleInstaller implements IModuleInstaller {
private isCondaAvailable: boolean | undefined;
public get displayName() {
return 'Pip';
}
constructor( @inject(IServiceContainer) serviceContainer: IServiceContainer) {
super(serviceContainer);
}
public isSupported(resource?: Uri): Promise<boolean> {
const pythonExecutionFactory = this.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory);
return pythonExecutionFactory.create(resource)
.then(proc => proc.isModuleInstalled('pip'))
.catch(() => false);
return this.isPipAvailable(resource);
}
protected async getExecutionInfo(moduleName: string, resource?: Uri): Promise<ExecutionInfo> {
const proxyArgs = [];
Expand All @@ -37,7 +33,7 @@ export class PipInstaller extends ModuleInstaller implements IModuleInstaller {
moduleName: 'pip'
};
}
private isPipAvailable(resource?: Uri) {
private isPipAvailable(resource?: Uri): Promise<boolean> {
const pythonExecutionFactory = this.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory);
return pythonExecutionFactory.create(resource)
.then(proc => proc.isModuleInstalled('pip'))
Expand Down
Loading