Skip to content

Commit f9e2596

Browse files
authored
Disable linter without workspaces (microsoft#241)
* Fix microsoft/vscode#37627 (microsoft#1368) * Version 0.7.0 of extension (microsoft#1381) Archive of 0.7.0 * Update README.md * Update README.md * fix readme * fixes #42 disable in workspace specific config
1 parent 7b0838b commit f9e2596

File tree

5 files changed

+119
-22
lines changed

5 files changed

+119
-22
lines changed

src/client/common/installer.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import * as os from 'os';
22
import * as vscode from 'vscode';
3-
import { commands, ConfigurationTarget, Disposable, OutputChannel, Terminal, Uri, window, workspace } from 'vscode';
3+
import { ConfigurationTarget, Uri, window, workspace } from 'vscode';
44
import * as settings from './configSettings';
55
import { isNotInstalledError } from './helpers';
6-
import { error } from './logger';
76
import { execPythonFile, getFullyQualifiedPythonInterpreterPath, IS_WINDOWS } from './utils';
87

98
export enum Product {
@@ -203,12 +202,13 @@ export class Installer implements vscode.Disposable {
203202
return InstallerResponse.Ignore;
204203
}
205204

206-
const installOption = ProductInstallationPrompt.has(product) ? ProductInstallationPrompt.get(product) : `Install ${productName}`;
205+
// tslint:disable-next-line:no-non-null-assertion
206+
const installOption = ProductInstallationPrompt.has(product) ? ProductInstallationPrompt.get(product)! : `Install ${productName}`;
207207
const disableOption = `Disable ${productTypeName}`;
208208
const dontShowAgain = 'Don\'t show this prompt again';
209209
const alternateFormatter = product === Product.autopep8 ? 'yapf' : 'autopep8';
210210
const useOtherFormatter = `Use '${alternateFormatter}' formatter`;
211-
const options = [];
211+
const options: string[] = [];
212212
options.push(installOption);
213213
if (productType === ProductType.Formatter) {
214214
options.push(...[useOtherFormatter]);
@@ -217,6 +217,9 @@ export class Installer implements vscode.Disposable {
217217
options.push(...[disableOption, dontShowAgain]);
218218
}
219219
const item = await window.showErrorMessage(`${productTypeName} ${productName} is not installed`, ...options);
220+
if (!item) {
221+
return InstallerResponse.Ignore;
222+
}
220223
switch (item) {
221224
case installOption: {
222225
return this.install(product, resource);
@@ -313,26 +316,28 @@ export class Installer implements vscode.Disposable {
313316
}
314317

315318
return installationPromise
316-
.then(() => this.isInstalled(product))
319+
.then(async () => this.isInstalled(product))
317320
.then(isInstalled => isInstalled ? InstallerResponse.Installed : InstallerResponse.Ignore);
318321
}
319322

320323
// tslint:disable-next-line:member-ordering
321-
public isInstalled(product: Product, resource?: Uri): Promise<boolean | undefined> {
324+
public async isInstalled(product: Product, resource?: Uri): Promise<boolean | undefined> {
322325
return isProductInstalled(product, resource);
323326
}
324327

325328
// tslint:disable-next-line:member-ordering no-any
326-
public uninstall(product: Product, resource?: Uri): Promise<any> {
329+
public async uninstall(product: Product, resource?: Uri): Promise<any> {
327330
return uninstallproduct(product, resource);
328331
}
329332
// tslint:disable-next-line:member-ordering
330-
public disableLinter(product: Product, resource: Uri) {
331-
if (resource && !workspace.getWorkspaceFolder(resource)) {
333+
public async disableLinter(product: Product, resource?: Uri) {
334+
if (resource && workspace.getWorkspaceFolder(resource)) {
332335
// tslint:disable-next-line:no-non-null-assertion
333336
const settingToDisable = SettingToDisableProduct.get(product)!;
334337
const pythonConfig = workspace.getConfiguration('python', resource);
335-
return pythonConfig.update(settingToDisable, false, ConfigurationTarget.Workspace);
338+
const isMultiroot = Array.isArray(workspace.workspaceFolders) && workspace.workspaceFolders.length > 1;
339+
const configTarget = isMultiroot ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace;
340+
return pythonConfig.update(settingToDisable, false, configTarget);
336341
} else {
337342
const pythonConfig = workspace.getConfiguration('python');
338343
return pythonConfig.update('linting.enabledWithoutWorkspace', false, true);
@@ -382,7 +387,7 @@ async function isProductInstalled(product: Product, resource?: Uri): Promise<boo
382387
}
383388

384389
// tslint:disable-next-line:no-any
385-
function uninstallproduct(product: Product, resource?: Uri): Promise<any> {
390+
async function uninstallproduct(product: Product, resource?: Uri): Promise<any> {
386391
if (!ProductUninstallScripts.has(product)) {
387392
return Promise.resolve();
388393
}

src/test/common.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ export type PythonSettingKeys = 'workspaceSymbols.enabled' | 'pythonPath' |
1414
'linting.prospectorEnabled' | 'linting.pydocstyleEnabled' | 'linting.mypyEnabled' |
1515
'unitTest.nosetestArgs' | 'unitTest.pyTestArgs' | 'unitTest.unittestArgs' |
1616
'formatting.formatOnSave' | 'formatting.provider' | 'sortImports.args' |
17-
'unitTest.nosetestsEnabled' | 'unitTest.pyTestEnabled' | 'unitTest.unittestEnabled';
17+
'unitTest.nosetestsEnabled' | 'unitTest.pyTestEnabled' | 'unitTest.unittestEnabled' |
18+
'linting.enabledWithoutWorkspace';
1819

19-
export async function updateSetting(setting: PythonSettingKeys, value: {}, resource: Uri, configTarget: ConfigurationTarget) {
20+
export async function updateSetting(setting: PythonSettingKeys, value: {}, resource: Uri | undefined, configTarget: ConfigurationTarget) {
2021
const settings = workspace.getConfiguration('python', resource);
2122
const currentValue = settings.inspect(setting);
2223
if (currentValue !== undefined && ((configTarget === ConfigurationTarget.Global && currentValue.globalValue === value) ||
@@ -50,8 +51,7 @@ export function retryAsync(wrapped: Function, retryCount: number = 2) {
5051
const reasons: any[] = [];
5152

5253
const makeCall = () => {
53-
// tslint:disable-next-line:no-unsafe-any no-any
54-
// tslint:disable-next-line:no-invalid-this
54+
// tslint:disable-next-line:no-unsafe-any no-any no-invalid-this
5555
wrapped.call(this, ...args)
5656
// tslint:disable-next-line:no-unsafe-any no-any
5757
.then(resolve, (reason: any) => {
@@ -86,7 +86,9 @@ async function setPythonPathInWorkspace(resource: string | Uri | undefined, conf
8686
}
8787
async function restoreGlobalPythonPathSetting(): Promise<void> {
8888
const pythonConfig = workspace.getConfiguration('python');
89-
const currentGlobalPythonPathSetting = pythonConfig.inspect('pythonPath').globalValue;
89+
// tslint:disable-next-line:no-non-null-assertion
90+
const currentGlobalPythonPathSetting = pythonConfig.inspect('pythonPath')!.globalValue;
91+
// tslint:disable-next-line:no-use-before-declare
9092
if (globalPythonPathSetting !== currentGlobalPythonPathSetting) {
9193
await pythonConfig.update('pythonPath', undefined, true);
9294
}
@@ -106,7 +108,8 @@ export async function deleteFile(file: string) {
106108
}
107109
}
108110

109-
const globalPythonPathSetting = workspace.getConfiguration('python').inspect('pythonPath').globalValue;
111+
// tslint:disable-next-line:no-non-null-assertion
112+
const globalPythonPathSetting = workspace.getConfiguration('python').inspect('pythonPath')!.globalValue;
110113
export const clearPythonPathInWorkspaceFolder = async (resource: string | Uri) => retryAsync(setPythonPathInWorkspace)(resource, ConfigurationTarget.WorkspaceFolder);
111114
export const setPythonPathInWorkspaceRoot = async (pythonPath: string) => retryAsync(setPythonPathInWorkspace)(undefined, ConfigurationTarget.Workspace, pythonPath);
112115
export const resetGlobalPythonPathSetting = async () => retryAsync(restoreGlobalPythonPathSetting)();
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as assert from 'assert';
2+
import * as path from 'path';
3+
import { ConfigurationTarget, Uri, workspace } from 'vscode';
4+
import { Installer, Product } from '../../client/common/installer';
5+
import { rootWorkspaceUri } from '../common';
6+
import { updateSetting } from '../common';
7+
import { closeActiveWindows, initializeTest, IS_MULTI_ROOT_TEST } from './../initialize';
8+
import { MockOutputChannel } from './../mockClasses';
9+
10+
// tslint:disable-next-line:no-suspicious-comment
11+
// TODO: Need to mock the command runner, to check what commands are being sent.
12+
// Instead of altering the environment.
13+
14+
suite('Installer', () => {
15+
let outputChannel: MockOutputChannel;
16+
let installer: Installer;
17+
const workspaceUri = Uri.file(path.join(__dirname, '..', '..', '..', 'src', 'test'));
18+
suiteSetup(async function () {
19+
if (!IS_MULTI_ROOT_TEST) {
20+
// tslint:disable-next-line:no-invalid-this
21+
this.skip();
22+
}
23+
outputChannel = new MockOutputChannel('Installer');
24+
installer = new Installer(outputChannel);
25+
await initializeTest();
26+
});
27+
setup(async () => {
28+
await initializeTest();
29+
await resetSettings();
30+
});
31+
suiteTeardown(async () => {
32+
await closeActiveWindows();
33+
await resetSettings();
34+
});
35+
teardown(closeActiveWindows);
36+
37+
async function resetSettings() {
38+
await updateSetting('linting.enabledWithoutWorkspace', true, undefined, ConfigurationTarget.Global);
39+
await updateSetting('linting.pylintEnabled', true, rootWorkspaceUri, ConfigurationTarget.Workspace);
40+
if (IS_MULTI_ROOT_TEST) {
41+
await updateSetting('linting.pylintEnabled', true, rootWorkspaceUri, ConfigurationTarget.WorkspaceFolder);
42+
}
43+
}
44+
45+
test('Disable linting of files contained in a multi-root workspace', async function () {
46+
if (!IS_MULTI_ROOT_TEST) {
47+
// tslint:disable-next-line:no-invalid-this
48+
this.skip();
49+
}
50+
await installer.disableLinter(Product.pylint, workspaceUri);
51+
const pythonWConfig = workspace.getConfiguration('python', workspaceUri);
52+
const value = pythonWConfig.inspect<boolean>('linting.pylintEnabled');
53+
// tslint:disable-next-line:no-non-null-assertion
54+
assert.equal(value!.workspaceValue, true, 'Workspace setting has been disabled');
55+
// tslint:disable-next-line:no-non-null-assertion
56+
assert.equal(value!.workspaceFolderValue, false, 'Workspace folder setting not disabled');
57+
});
58+
});

src/test/common/installer.test.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import * as assert from 'assert';
22
import * as path from 'path';
3-
import { Uri } from 'vscode';
3+
import { ConfigurationTarget, Uri, workspace } from 'vscode';
44
import { EnumEx } from '../../client/common/enumUtils';
55
import { Installer, Product } from '../../client/common/installer';
6+
import { rootWorkspaceUri } from '../common';
7+
import { updateSetting } from '../common';
68
import { closeActiveWindows, initializeTest, IS_MULTI_ROOT_TEST, IS_TRAVIS } from './../initialize';
79
import { MockOutputChannel } from './../mockClasses';
810

11+
// tslint:disable-next-line:no-suspicious-comment
912
// TODO: Need to mock the command runner, to check what commands are being sent.
1013
// Instead of altering the environment.
1114

@@ -19,16 +22,27 @@ suite('Installer', () => {
1922
installer = new Installer(outputChannel);
2023
await initializeTest();
2124
});
22-
setup(initializeTest);
23-
suiteTeardown(closeActiveWindows);
25+
setup(async () => {
26+
await initializeTest();
27+
await resetSettings();
28+
});
29+
suiteTeardown(async () => {
30+
await closeActiveWindows();
31+
await resetSettings();
32+
});
2433
teardown(closeActiveWindows);
2534

35+
async function resetSettings() {
36+
await updateSetting('linting.enabledWithoutWorkspace', true, undefined, ConfigurationTarget.Global);
37+
await updateSetting('linting.pylintEnabled', true, rootWorkspaceUri, ConfigurationTarget.Workspace);
38+
}
39+
2640
async function testUninstallingProduct(product: Product) {
2741
let isInstalled = await installer.isInstalled(product, resource);
2842
if (isInstalled) {
2943
await installer.uninstall(product, resource);
3044
isInstalled = await installer.isInstalled(product, resource);
31-
// Someimtes installation doesn't work on Travis
45+
// Sometimes installation doesn't work on Travis
3246
if (!IS_TRAVIS) {
3347
assert.equal(isInstalled, false, 'Product uninstall failed');
3448
}
@@ -50,7 +64,7 @@ suite('Installer', () => {
5064
await installer.install(product, resource);
5165
}
5266
const checkIsInstalledAgain = await installer.isInstalled(product, resource);
53-
// Someimtes installation doesn't work on Travis
67+
// Sometimes installation doesn't work on Travis
5468
if (!IS_TRAVIS) {
5569
assert.notEqual(checkIsInstalledAgain, false, 'Product installation failed');
5670
}
@@ -63,4 +77,20 @@ suite('Installer', () => {
6377
await testInstallingProduct(prod.value);
6478
});
6579
});
80+
81+
test('Disable linting of files not contained in a workspace', async () => {
82+
await installer.disableLinter(Product.pylint, undefined);
83+
const pythonConfig = workspace.getConfiguration('python');
84+
assert.equal(pythonConfig.get<boolean>('linting.enabledWithoutWorkspace'), false, 'Incorrect setting');
85+
});
86+
87+
test('Disable linting of files contained in a workspace', async function () {
88+
if (IS_MULTI_ROOT_TEST) {
89+
// tslint:disable-next-line:no-invalid-this
90+
this.skip();
91+
}
92+
await installer.disableLinter(Product.pylint, workspaceUri);
93+
const pythonConfig = workspace.getConfiguration('python', workspaceUri);
94+
assert.equal(pythonConfig.get<boolean>('linting.pylintEnabled'), false, 'Incorrect setting');
95+
});
6696
});

tslint.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"PromiseLike"
4444
],
4545
"completed-docs": false,
46+
"no-backbone-get-set-outside-model": false,
4647
"no-unsafe-any": false
4748
}
4849
}

0 commit comments

Comments
 (0)