diff --git a/news/2 Fixes/2198.md b/news/2 Fixes/2198.md new file mode 100644 index 000000000000..5859dc459b08 --- /dev/null +++ b/news/2 Fixes/2198.md @@ -0,0 +1,2 @@ +Change linter message parsing so it respects `python.linting.maxNumberOfProblems`. +(thanks [Scott Saponas](https://github.com/saponas/)) diff --git a/src/client/linters/baseLinter.ts b/src/client/linters/baseLinter.ts index 51319c0f581b..a814b1aba9ff 100644 --- a/src/client/linters/baseLinter.ts +++ b/src/client/linters/baseLinter.ts @@ -149,21 +149,21 @@ export abstract class BaseLinter implements ILinter { } private parseLines(outputLines: string[], regEx: string): ILintMessage[] { - return outputLines - .filter((value, index) => index <= this.pythonSettings.linting.maxNumberOfProblems) - .map(line => { - try { - const msg = this.parseLine(line, regEx); - if (msg) { - return msg; + const messages: ILintMessage[] = []; + for (const line of outputLines) { + try { + const msg = this.parseLine(line, regEx); + if (msg) { + messages.push(msg); + if (messages.length >= this.pythonSettings.linting.maxNumberOfProblems) { + break; } - } catch (ex) { - this.logger.logError(`Linter '${this.info.id}' failed to parse the line '${line}.`, ex); } - return; - }) - .filter(item => item !== undefined) - .map(item => item!); + } catch (ex) { + this.logger.logError(`Linter '${this.info.id}' failed to parse the line '${line}.`, ex); + } + } + return messages; } private displayLinterResultHeader(data: string) { diff --git a/src/test/linters/lint.test.ts b/src/test/linters/lint.test.ts index 737a2686729c..8b9d702228ad 100644 --- a/src/test/linters/lint.test.ts +++ b/src/test/linters/lint.test.ts @@ -23,6 +23,7 @@ const pep8ConfigPath = path.join(pythoFilesPath, 'pep8config'); const pydocstyleConfigPath27 = path.join(pythoFilesPath, 'pydocstyleconfig27'); const pylintConfigPath = path.join(pythoFilesPath, 'pylintconfig'); const fileToLint = path.join(pythoFilesPath, 'file.py'); +const threeLineLintsPath = path.join(pythoFilesPath, 'threeLineLints.py'); const pylintMessagesToBeReturned: ILintMessage[] = [ { line: 24, column: 0, severity: LintMessageSeverity.Information, code: 'I0011', message: 'Locally disabling no-member (E1101)', provider: '', type: '' }, @@ -279,4 +280,22 @@ suite('Linting - General Tests', () => { assert.notEqual(messages!.filter(x => x.source === 'pylint').length, 0, 'No pylint messages.'); assert.notEqual(messages!.filter(x => x.source === 'flake8').length, 0, 'No flake8 messages.'); }); + // tslint:disable-next-line:no-any + async function testLinterMessageCount(product: Product, pythonFile: string, messageCountToBeReceived: number): Promise { + const outputChannel = ioc.serviceContainer.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); + const cancelToken = new CancellationTokenSource(); + const document = await workspace.openTextDocument(pythonFile); + + await linterManager.setActiveLintersAsync([product], document.uri); + const linter = linterManager.createLinter(product, outputChannel, ioc.serviceContainer); + + const messages = await linter.lint(document, cancelToken.token); + assert.equal(messages.length, messageCountToBeReceived, 'Expected number of lint errors does not match lint error count'); + } + test('Three line output counted as one message', async () => { + const maxErrors = 5; + const target = IS_MULTI_ROOT_TEST ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace; + await configService.updateSettingAsync('linting.maxNumberOfProblems', maxErrors, rootWorkspaceUri, target); + await testLinterMessageCount(Product.pylint, threeLineLintsPath, maxErrors); + }); }); diff --git a/src/test/pythonFiles/linting/threeLineLints.py b/src/test/pythonFiles/linting/threeLineLints.py new file mode 100644 index 000000000000..e8b578d93f11 --- /dev/null +++ b/src/test/pythonFiles/linting/threeLineLints.py @@ -0,0 +1,24 @@ +"""pylint messages with three lines of output""" + +__revision__ = None + +class Foo(object): + + def __init__(self): + pass + + def meth1(self,arg): + """missing a space between 'self' and 'arg'. This should trigger the + following three line lint warning:: + + C: 10, 0: Exactly one space required after comma + def meth1(self,arg): + ^ (bad-whitespace) + + The following three lines of tuples should also cause three-line lint + errors due to "Exactly one space required after comma" messages. + """ + a = (1,2) + b = (1,2) + c = (1,2) + print (self)