Skip to content

Commit d572335

Browse files
committed
mypy support
1 parent ca153a7 commit d572335

File tree

5 files changed

+82
-9
lines changed

5 files changed

+82
-9
lines changed

package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,11 @@
469469
"default": false,
470470
"description": "Whether to lint Python files using pydocstyle"
471471
},
472+
"python.linting.mypyEnabled": {
473+
"type": "boolean",
474+
"default": false,
475+
"description": "Whether to lint Python files using mypy."
476+
},
472477
"python.linting.lintOnTextChange": {
473478
"type": "boolean",
474479
"default": true,
@@ -564,6 +569,11 @@
564569
"default": "pydocstyle",
565570
"description": "Path to pydocstyle, you can use a custom version of pydocstyle by modifying this setting to include the full path."
566571
},
572+
"python.linting.mypyPath": {
573+
"type": "string",
574+
"default": "mypy",
575+
"description": "Path to mypy, you can use a custom version of pylint by modifying this setting to include the full path."
576+
},
567577
"python.linting.prospectorArgs": {
568578
"type": "array",
569579
"description": "Arguments passed in. Each argument is a separate item in the array.",
@@ -604,6 +614,14 @@
604614
"type": "string"
605615
}
606616
},
617+
"python.linting.mypyArgs": {
618+
"type": "array",
619+
"description": "Arguments passed in. Each argument is a separate item in the array.",
620+
"default": [],
621+
"items": {
622+
"type": "string"
623+
}
624+
},
607625
"python.linting.outputWindow": {
608626
"type": "string",
609627
"default": "Python",

src/client/common/configSettings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ export interface ILintingSettings {
5555
flake8Path: string;
5656
pydocStylePath: string;
5757
outputWindow: string;
58+
mypyEnabled: boolean;
59+
mypyArgs: string[];
60+
mypyPath: string;
5861
}
5962
export interface IFormattingSettings {
6063
provider: string;

src/client/linters/baseLinter.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,23 @@ export abstract class BaseLinter {
7979
match.line = Number(<any>match.line);
8080
match.column = Number(<any>match.column);
8181

82-
let sourceLine = txtDocumentLines[match.line - 1];
83-
let sourceStart = sourceLine.substring(match.column - 1);
84-
let endCol = txtDocumentLines[match.line - 1].length;
85-
86-
// try to get the first word from the startig position
87-
let possibleProblemWords = sourceStart.match(/\w+/g);
8882
let possibleWord: string;
89-
if (possibleProblemWords != null && possibleProblemWords.length > 0 && sourceStart.startsWith(possibleProblemWords[0])) {
90-
possibleWord = possibleProblemWords[0];
83+
if (!isNaN(match.column)) {
84+
let sourceLine = txtDocumentLines[match.line - 1];
85+
let sourceStart = sourceLine.substring(match.column - 1);
86+
let endCol = txtDocumentLines[match.line - 1].length;
87+
88+
// try to get the first word from the startig position
89+
let possibleProblemWords = sourceStart.match(/\w+/g);
90+
if (possibleProblemWords != null && possibleProblemWords.length > 0 && sourceStart.startsWith(possibleProblemWords[0])) {
91+
possibleWord = possibleProblemWords[0];
92+
}
9193
}
9294

9395
diagnostics.push({
9496
code: match.code,
9597
message: match.message,
96-
column: match.column,
98+
column: isNaN(match.column) ? 0 : match.column,
9799
line: match.line,
98100
possibleWord: possibleWord,
99101
type: match.type,

src/client/linters/mypy.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
import * as path from 'path';
4+
import * as baseLinter from './baseLinter';
5+
import {OutputChannel, workspace} from 'vscode';
6+
7+
const REGEX = '(?<file>.py):(?<line>\\d+): (?<type>\\w+): (?<message>.*)\\r?(\\n|$)';
8+
9+
export class Linter extends baseLinter.BaseLinter {
10+
constructor(outputChannel: OutputChannel, workspaceRootPath: string) {
11+
super('mypy', outputChannel, workspaceRootPath);
12+
}
13+
private parseMessagesSeverity(category: string): baseLinter.LintMessageSeverity {
14+
switch (category) {
15+
case 'error': {
16+
return baseLinter.LintMessageSeverity.Error;
17+
}
18+
case 'note': {
19+
return baseLinter.LintMessageSeverity.Hint;
20+
}
21+
default: {
22+
return baseLinter.LintMessageSeverity.Information;
23+
}
24+
}
25+
}
26+
27+
public isEnabled(): Boolean {
28+
return this.pythonSettings.linting.mypyEnabled;
29+
}
30+
public runLinter(filePath: string, txtDocumentLines: string[]): Promise<baseLinter.ILintMessage[]> {
31+
if (!this.pythonSettings.linting.mypyEnabled) {
32+
return Promise.resolve([]);
33+
}
34+
35+
let mypyPath = this.pythonSettings.linting.mypyPath;
36+
let mypyArgs = Array.isArray(this.pythonSettings.linting.mypyArgs) ? this.pythonSettings.linting.mypyArgs : [];
37+
return new Promise<baseLinter.ILintMessage[]>((resolve, reject) => {
38+
this.run(mypyPath, mypyArgs.concat([filePath]), filePath, txtDocumentLines, this.workspaceRootPath, REGEX).then(messages => {
39+
messages.forEach(msg => {
40+
msg.severity = this.parseMessagesSeverity(msg.type);
41+
msg.code = msg.type;
42+
});
43+
44+
resolve(messages);
45+
}, reject);
46+
});
47+
}
48+
}

src/client/providers/lintProvider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as pylint from './../linters/pylint';
88
import * as pep8 from './../linters/pep8Linter';
99
import * as flake8 from './../linters/flake8';
1010
import * as pydocstyle from './../linters/pydocstyle';
11+
import * as mypy from './../linters/mypy';
1112
import * as settings from '../common/configSettings';
1213
import * as telemetryHelper from '../common/telemetry';
1314
import * as telemetryContracts from '../common/telemetryContracts';
@@ -67,6 +68,7 @@ export class LintProvider extends vscode.Disposable {
6768
this.linters.push(new pep8.Linter(this.outputChannel, this.workspaceRootPath));
6869
this.linters.push(new flake8.Linter(this.outputChannel, this.workspaceRootPath));
6970
this.linters.push(new pydocstyle.Linter(this.outputChannel, this.workspaceRootPath));
71+
this.linters.push(new mypy.Linter(this.outputChannel, this.workspaceRootPath));
7072

7173
let disposable = vscode.workspace.onDidSaveTextDocument((e) => {
7274
if (e.languageId !== 'python' || !this.settings.linting.enabled || !this.settings.linting.lintOnSave) {

0 commit comments

Comments
 (0)