Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions news/1 Enhancements/15170.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added `python.linting.cwd` to change the working directory of the linters (thanks [Matthew Shirley](https://github.com/matthewshirley))
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,12 @@
"description": "Whether to lint Python files.",
"scope": "resource"
},
"python.linting.cwd": {
"type": "string",
"default": null,
"description": "Optional working directory for linters.",
"scope": "resource"
},
"python.linting.flake8Args": {
"type": "array",
"description": "Arguments passed in. Each argument is a separate item in the array.",
Expand Down
5 changes: 5 additions & 0 deletions src/client/common/configSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ export class PythonSettings implements IPythonSettings {
? this.linting
: {
enabled: false,
cwd: undefined,
ignorePatterns: [],
flake8Args: [],
flake8Enabled: false,
Expand Down Expand Up @@ -409,6 +410,10 @@ export class PythonSettings implements IPythonSettings {
this.linting.mypyPath = getAbsolutePath(systemVariables.resolveAny(this.linting.mypyPath), workspaceRoot);
this.linting.banditPath = getAbsolutePath(systemVariables.resolveAny(this.linting.banditPath), workspaceRoot);

if (this.linting.cwd) {
this.linting.cwd = getAbsolutePath(systemVariables.resolveAny(this.linting.cwd), workspaceRoot);
}

const formattingSettings = systemVariables.resolveAny(pythonSettings.get<IFormattingSettings>('formatting'))!;
if (this.formatting) {
Object.assign<IFormattingSettings, IFormattingSettings>(this.formatting, formattingSettings);
Expand Down
1 change: 1 addition & 0 deletions src/client/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ export interface ILintingSettings {
readonly pycodestyleCategorySeverity: IPycodestyleCategorySeverity;
readonly flake8CategorySeverity: Flake8CategorySeverity;
readonly mypyCategorySeverity: IMypyCategorySeverity;
cwd?: string;
prospectorPath: string;
pylintPath: string;
pycodestylePath: string;
Expand Down
6 changes: 5 additions & 1 deletion src/client/linters/baseLinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ export abstract class BaseLinter implements ILinter {
workspaceFolder && typeof workspaceFolder.uri.fsPath === 'string' ? workspaceFolder.uri.fsPath : undefined;
return typeof workspaceRootPath === 'string' ? workspaceRootPath : path.dirname(document.uri.fsPath);
}

protected getWorkingDirectoryPath(document: vscode.TextDocument): string {
return this._pythonSettings.linting.cwd || this.getWorkspaceRootPath(document);
}
protected abstract runLinter(
document: vscode.TextDocument,
cancellation: vscode.CancellationToken,
Expand Down Expand Up @@ -138,7 +142,7 @@ export abstract class BaseLinter implements ILinter {
return [];
}
const executionInfo = this.info.getExecutionInfo(args, document.uri);
const cwd = this.getWorkspaceRootPath(document);
const cwd = this.getWorkingDirectoryPath(document);
const pythonToolsExecutionService = this.serviceContainer.get<IPythonToolExecutionService>(
IPythonToolExecutionService,
);
Expand Down
2 changes: 1 addition & 1 deletion src/client/linters/prospector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class Prospector extends BaseLinter {
}

protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise<ILintMessage[]> {
const cwd = this.getWorkspaceRootPath(document);
const cwd = this.getWorkingDirectoryPath(document);
const relativePath = path.relative(cwd, document.uri.fsPath);
return this.run(['--absolute-paths', '--output-format=json', relativePath], document, cancellation);
}
Expand Down
4 changes: 2 additions & 2 deletions src/client/linters/pylint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ export class Pylint extends BaseLinter {
this.info.linterArgs(uri).length === 0 &&
// Check pylintrc next to the file or above up to and including the workspace root
!(await Pylint.hasConfigurationFileInWorkspace(this.fileSystem, path.dirname(uri.fsPath), workspaceRoot)) &&
// Check for pylintrc at the root and above
// Check for pylintrc at the cwd and above
!(await Pylint.hasConfigurationFile(
this.fileSystem,
this.getWorkspaceRootPath(document),
this.getWorkingDirectoryPath(document),
this.platformService,
))
) {
Expand Down
2 changes: 2 additions & 0 deletions src/test/linters/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export function throwUnknownProduct(product: Product) {

export class LintingSettings {
public enabled: boolean;
public cwd?: string;
public ignorePatterns: string[];
public prospectorEnabled: boolean;
public prospectorArgs: string[];
Expand Down Expand Up @@ -107,6 +108,7 @@ export class LintingSettings {
// mostly from configSettings.ts

this.enabled = true;
this.cwd = undefined;
this.ignorePatterns = [];
this.lintOnSave = false;
this.maxNumberOfProblems = 100;
Expand Down
1 change: 1 addition & 0 deletions src/test/linters/lint.args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ suite('Linting - Arguments', () => {
const lintSettings = TypeMoq.Mock.ofType<ILintingSettings>();
lintSettings.setup((x) => x.enabled).returns(() => true);
lintSettings.setup((x) => x.lintOnSave).returns(() => true);
lintSettings.setup((x) => x.cwd).returns(() => undefined);

settings = TypeMoq.Mock.ofType<IPythonSettings>();
settings.setup((x) => x.linting).returns(() => lintSettings.object);
Expand Down
13 changes: 13 additions & 0 deletions src/test/linters/lint.functional.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -846,4 +846,17 @@ suite('Linting Functional Tests', () => {
maxErrors,
);
});

test('Linters use config in cwd directory', async () => {
const maxErrors = 0;
const fixture = new TestFixture();
fixture.lintingSettings.cwd = path.join(pythonFilesDir, 'pylintcwd');

await testLinterMessageCount(
fixture,
Product.pylint,
path.join(pythonFilesDir, 'threeLineLints.py'),
maxErrors,
);
});
});
2 changes: 1 addition & 1 deletion src/test/linters/pylint.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ suite('Pylint - Function runLinter()', () => {
): Promise<ILintMessage[]> {
return super.runLinter(document, cancellation);
}
public getWorkspaceRootPath(_document: vscode.TextDocument): string {
public getWorkingDirectoryPath(_document: vscode.TextDocument): string {
return 'path/to/workspaceRoot';
}
}
Expand Down
1 change: 1 addition & 0 deletions src/test/mockClasses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export class MockStatusBarItem implements vscode.StatusBarItem {

export class MockLintingSettings implements ILintingSettings {
public enabled!: boolean;
public cwd?: string;
public ignorePatterns!: string[];
public prospectorEnabled!: boolean;
public prospectorArgs!: string[];
Expand Down
2 changes: 2 additions & 0 deletions src/test/pythonFiles/linting/cwd/.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[MESSAGES CONTROL]
disable=C0326,I0011,I0012,C0304,C0103,W0613,E0001,E1101