Skip to content

Commit bbdba53

Browse files
author
Matthew Shirley
authored
Expose a setting to allow a user modify the working directory of linters (microsoft#15171)
* expose a setting to change the working directory of linters * set linting cwd after linters * address ci failure * default cwd setting should be undefined * add method that determines whether to return cwd or workspace root * add functional test that asserts no errors are thrown if cwd is set * add thanks to self * update test runner to force cwd path * update test cwd settings * update mock to return undefined cwd
1 parent 1a83891 commit bbdba53

13 files changed

Lines changed: 41 additions & 5 deletions

File tree

news/1 Enhancements/15170.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `python.linting.cwd` to change the working directory of the linters (thanks [Matthew Shirley](https://github.com/matthewshirley))

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,12 @@
12691269
"description": "Whether to lint Python files.",
12701270
"scope": "resource"
12711271
},
1272+
"python.linting.cwd": {
1273+
"type": "string",
1274+
"default": null,
1275+
"description": "Optional working directory for linters.",
1276+
"scope": "resource"
1277+
},
12721278
"python.linting.flake8Args": {
12731279
"type": "array",
12741280
"description": "Arguments passed in. Each argument is a separate item in the array.",

src/client/common/configSettings.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ export class PythonSettings implements IPythonSettings {
349349
? this.linting
350350
: {
351351
enabled: false,
352+
cwd: undefined,
352353
ignorePatterns: [],
353354
flake8Args: [],
354355
flake8Enabled: false,
@@ -419,6 +420,10 @@ export class PythonSettings implements IPythonSettings {
419420
this.linting.mypyPath = getAbsolutePath(systemVariables.resolveAny(this.linting.mypyPath), workspaceRoot);
420421
this.linting.banditPath = getAbsolutePath(systemVariables.resolveAny(this.linting.banditPath), workspaceRoot);
421422

423+
if (this.linting.cwd) {
424+
this.linting.cwd = getAbsolutePath(systemVariables.resolveAny(this.linting.cwd), workspaceRoot);
425+
}
426+
422427
const formattingSettings = systemVariables.resolveAny(pythonSettings.get<IFormattingSettings>('formatting'))!;
423428
if (this.formatting) {
424429
Object.assign<IFormattingSettings, IFormattingSettings>(this.formatting, formattingSettings);

src/client/common/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ export interface ILintingSettings {
262262
readonly pycodestyleCategorySeverity: IPycodestyleCategorySeverity;
263263
readonly flake8CategorySeverity: Flake8CategorySeverity;
264264
readonly mypyCategorySeverity: IMypyCategorySeverity;
265+
cwd?: string;
265266
prospectorPath: string;
266267
pylintPath: string;
267268
pycodestylePath: string;

src/client/linters/baseLinter.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ export abstract class BaseLinter implements ILinter {
101101
workspaceFolder && typeof workspaceFolder.uri.fsPath === 'string' ? workspaceFolder.uri.fsPath : undefined;
102102
return typeof workspaceRootPath === 'string' ? workspaceRootPath : path.dirname(document.uri.fsPath);
103103
}
104+
105+
protected getWorkingDirectoryPath(document: vscode.TextDocument): string {
106+
return this._pythonSettings.linting.cwd || this.getWorkspaceRootPath(document);
107+
}
104108
protected abstract runLinter(
105109
document: vscode.TextDocument,
106110
cancellation: vscode.CancellationToken,
@@ -138,7 +142,7 @@ export abstract class BaseLinter implements ILinter {
138142
return [];
139143
}
140144
const executionInfo = this.info.getExecutionInfo(args, document.uri);
141-
const cwd = this.getWorkspaceRootPath(document);
145+
const cwd = this.getWorkingDirectoryPath(document);
142146
const pythonToolsExecutionService = this.serviceContainer.get<IPythonToolExecutionService>(
143147
IPythonToolExecutionService,
144148
);

src/client/linters/prospector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export class Prospector extends BaseLinter {
3030
}
3131

3232
protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise<ILintMessage[]> {
33-
const cwd = this.getWorkspaceRootPath(document);
33+
const cwd = this.getWorkingDirectoryPath(document);
3434
const relativePath = path.relative(cwd, document.uri.fsPath);
3535
return this.run(['--absolute-paths', '--output-format=json', relativePath], document, cancellation);
3636
}

src/client/linters/pylint.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ export class Pylint extends BaseLinter {
3939
this.info.linterArgs(uri).length === 0 &&
4040
// Check pylintrc next to the file or above up to and including the workspace root
4141
!(await Pylint.hasConfigurationFileInWorkspace(this.fileSystem, path.dirname(uri.fsPath), workspaceRoot)) &&
42-
// Check for pylintrc at the root and above
42+
// Check for pylintrc at the cwd and above
4343
!(await Pylint.hasConfigurationFile(
4444
this.fileSystem,
45-
this.getWorkspaceRootPath(document),
45+
this.getWorkingDirectoryPath(document),
4646
this.platformService,
4747
))
4848
) {

src/test/linters/common.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export function throwUnknownProduct(product: Product) {
7070

7171
export class LintingSettings {
7272
public enabled: boolean;
73+
public cwd?: string;
7374
public ignorePatterns: string[];
7475
public prospectorEnabled: boolean;
7576
public prospectorArgs: string[];
@@ -107,6 +108,7 @@ export class LintingSettings {
107108
// mostly from configSettings.ts
108109

109110
this.enabled = true;
111+
this.cwd = undefined;
110112
this.ignorePatterns = [];
111113
this.lintOnSave = false;
112114
this.maxNumberOfProblems = 100;

src/test/linters/lint.args.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ suite('Linting - Arguments', () => {
102102
const lintSettings = TypeMoq.Mock.ofType<ILintingSettings>();
103103
lintSettings.setup((x) => x.enabled).returns(() => true);
104104
lintSettings.setup((x) => x.lintOnSave).returns(() => true);
105+
lintSettings.setup((x) => x.cwd).returns(() => undefined);
105106

106107
settings = TypeMoq.Mock.ofType<IPythonSettings>();
107108
settings.setup((x) => x.linting).returns(() => lintSettings.object);

src/test/linters/lint.functional.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,4 +877,17 @@ suite('Linting Functional Tests', () => {
877877
maxErrors,
878878
);
879879
});
880+
881+
test('Linters use config in cwd directory', async () => {
882+
const maxErrors = 0;
883+
const fixture = new TestFixture();
884+
fixture.lintingSettings.cwd = path.join(pythonFilesDir, 'pylintcwd');
885+
886+
await testLinterMessageCount(
887+
fixture,
888+
Product.pylint,
889+
path.join(pythonFilesDir, 'threeLineLints.py'),
890+
maxErrors,
891+
);
892+
});
880893
});

0 commit comments

Comments
 (0)