Skip to content

Commit 49d0928

Browse files
committed
added support for pydocstyle #56
1 parent 77d1e7f commit 49d0928

File tree

6 files changed

+119
-2
lines changed

6 files changed

+119
-2
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Linting, Debugging (multi-threaded, web apps, remote), Intellisense, auto-comple
55
Once installed, do remember to [configure the path](https://github.com/DonJayamanne/pythonVSCode/wiki/Python-Path-and-Version) to the python executable.
66

77
##Features
8-
* Linting (PyLint, Pep8, Flake8 with config files and plugins)
8+
* Linting (PyLint, Pep8, Flake8, pydocstyle with config files and plugins)
99
* Intellisense and autocompletion
1010
* Code formatting (autopep8, yapf, with config files)
1111
* Renaming, Viewing references, Going to definitions, Go to Symbols
@@ -49,6 +49,7 @@ Once installed, do remember to [configure the path](https://github.com/DonJayama
4949
+ pylint can be turned on/off (default is on), supports standard configuaration files
5050
+ pep8 can be turned on/off (default is off), supports standard configuaration files
5151
+ flake8 can be turned on/off (default is on), supports standard configuaration files
52+
+ pydocstyle can be turned on/off (default is on), supports standard configuaration files
5253
+ Different categories of errors reported by pylint can be configured as warnings, errors, information or hits
5354
+ Path to pylint, pep8 and flake8 and pep8 can be configured
5455
+ Custom plugins such as pylint plugin for Django can be easily used by modifying the settings as follows:
@@ -94,6 +95,8 @@ Once installed, do remember to [configure the path](https://github.com/DonJayama
9495
+ pip install pep8
9596
* Flake8 is installed for linting (optional)
9697
+ pip install flake8
98+
* pydocstyle is installed for linting (optional)
99+
+ pip install pydocstyle
97100
* Autopep8 is installed for code formatting (optional)
98101
+ pip install pep8
99102
+ pip install --upgrade autopep8
@@ -104,6 +107,9 @@ Once installed, do remember to [configure the path](https://github.com/DonJayama
104107

105108
## Change Log
106109

110+
### Version 0.3.6
111+
* Added support for linting using pydocstyle [#56](https://github.com/DonJayamanne/pythonVSCode/issues/56)
112+
107113
### Version 0.3.5
108114
* Fixed printing of unicode characters when evaulating expressions [#73](https://github.com/DonJayamanne/pythonVSCode/issues/73)
109115

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@
270270
"default": false,
271271
"description": "Whether to lint Python files using flake8"
272272
},
273+
"python.linting.pydocstyleEnabled": {
274+
"type": "boolean",
275+
"default": false,
276+
"description": "Whether to lint Python files using pydocstyle"
277+
},
273278
"python.linting.lintOnTextChange": {
274279
"type": "boolean",
275280
"default": true,
@@ -355,6 +360,11 @@
355360
"default": "flake8",
356361
"description": "Path to flake8, you can use a custom version of flake8 by modifying this setting to include the full path."
357362
},
363+
"python.linting.pydocStylePath": {
364+
"type": "string",
365+
"default": "pydocstyle",
366+
"description": "Path to pydocstyle, you can use a custom version of pydocstyle by modifying this setting to include the full path."
367+
},
358368
"python.formatting.provider": {
359369
"type": "string",
360370
"default": "autopep8",

src/client/common/configSettings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ export interface ILintingSettings {
2828
pylintEnabled: boolean;
2929
pep8Enabled: boolean;
3030
flake8Enabled: boolean;
31+
pydocstyleEnabled: boolean;
3132
lintOnTextChange: boolean;
3233
lintOnSave: boolean;
3334
maxNumberOfProblems: number;
3435
pylintCategorySeverity: IPylintCategorySeverity;
3536
pylintPath: string;
3637
pep8Path: string;
3738
flake8Path: string;
39+
pydocStylePath: string;
3840
}
3941
export interface IFormattingSettings {
4042
provider: string;

src/client/linters/baseLinter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export enum LintMessageSeverity {
3434
Information
3535
}
3636

37-
function matchNamedRegEx(data, regex): IRegexGroup {
37+
export function matchNamedRegEx(data, regex): IRegexGroup {
3838
if (NamedRegexp === null) {
3939
NamedRegexp = require('named-js-regexp');
4040
}

src/client/linters/pydocstyle.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'use strict';
2+
3+
import * as path from 'path';
4+
import * as baseLinter from './baseLinter';
5+
import {ILintMessage} from './baseLinter';
6+
import * as settings from './../common/configSettings';
7+
import {OutputChannel, window} from 'vscode';
8+
import { exec } from 'child_process';
9+
import {sendCommand} from './../common/childProc';
10+
11+
export class Linter extends baseLinter.BaseLinter {
12+
constructor(rootDir: string, pythonSettings: settings.IPythonSettings, outputChannel: OutputChannel) {
13+
super("pydocstyle", pythonSettings, outputChannel);
14+
}
15+
16+
public runLinter(filePath: string, txtDocumentLines: string[]): Promise<baseLinter.ILintMessage[]> {
17+
if (!this.pythonSettings.linting.pydocstyleEnabled) {
18+
return Promise.resolve([]);
19+
}
20+
21+
var pydocStylePath = this.pythonSettings.linting.pydocStylePath;
22+
var cmdLine = `${pydocStylePath} "${filePath}"`;
23+
return new Promise<baseLinter.ILintMessage[]>(resolve => {
24+
this.run(cmdLine, filePath, txtDocumentLines).then(messages => {
25+
//All messages in pep8 are treated as warnings for now
26+
messages.forEach(msg => {
27+
msg.severity = baseLinter.LintMessageSeverity.Information;
28+
});
29+
30+
resolve(messages);
31+
});
32+
});
33+
}
34+
35+
protected run(commandLine: string, filePath: string, txtDocumentLines: string[]): Promise<ILintMessage[]> {
36+
var outputChannel = this.outputChannel;
37+
var linterId = this.Id;
38+
39+
return new Promise<ILintMessage[]>((resolve, reject) => {
40+
var fileDir = path.dirname(filePath);
41+
sendCommand(commandLine, fileDir, true).then(data => {
42+
outputChannel.clear();
43+
outputChannel.append(data);
44+
var outputLines = data.split(/\r?\n/g);
45+
var diagnostics: ILintMessage[] = [];
46+
var baseFileName = path.basename(filePath);
47+
48+
//Remember, the first line of the response contains the file name and line number, the next line contains the error message
49+
//So we have two lines per message, hence we need to take lines in pairs
50+
var maxLines = this.pythonSettings.linting.maxNumberOfProblems * 2;
51+
//First line is almost always empty
52+
while (outputLines.length > 0 && outputLines[0].trim().length === 0) {
53+
outputLines.splice(0, 1);
54+
}
55+
outputLines = outputLines.filter((value, index) => index < maxLines);
56+
57+
//Iterate through the lines (skipping the messages)
58+
//So, just iterate the response in pairs
59+
for (var counter = 0; counter < outputLines.length; counter = counter + 2) {
60+
try {
61+
var line = outputLines[counter];
62+
if (line.trim().length === 0) {
63+
continue;
64+
}
65+
var messageLine = outputLines[counter + 1];
66+
var lineNumber = parseInt(line.substring(line.indexOf(baseFileName) + baseFileName.length + 1));
67+
var code = messageLine.substring(0, messageLine.indexOf(":")).trim();
68+
var message = messageLine.substring(messageLine.indexOf(":") + 1).trim();
69+
70+
var sourceLine = txtDocumentLines[lineNumber - 1];
71+
var trmmedSourceLine = sourceLine.trim();
72+
var sourceStart = sourceLine.indexOf(trmmedSourceLine);
73+
var endCol = sourceStart + trmmedSourceLine.length;
74+
75+
diagnostics.push({
76+
code: code,
77+
message: message,
78+
column: sourceStart,
79+
line: lineNumber,
80+
type: "",
81+
provider: this.Id
82+
});
83+
}
84+
catch (ex) {
85+
//Hmm, need to handle this later
86+
var y = "";
87+
}
88+
}
89+
90+
resolve(diagnostics);
91+
}, error => {
92+
outputChannel.appendLine(`Linting with ${linterId} failed. If not installed please turn if off in settings.\n ${error}`);
93+
window.showInformationMessage(`Linting with ${linterId} failed. If not installed please turn if off in settings. View Python output for details.`);
94+
});
95+
});
96+
}
97+
}

src/client/providers/lintProvider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as linter from '../linters/baseLinter';
99
import * as pylint from './../linters/pylint';
1010
import * as pep8 from './../linters/pep8Linter';
1111
import * as flake8 from './../linters/flake8';
12+
import * as pydocstyle from './../linters/pydocstyle';
1213
import * as settings from '../common/configSettings';
1314

1415
const FILE_PROTOCOL = "file:///"
@@ -67,6 +68,7 @@ export class LintProvider extends vscode.Disposable {
6768
this.linters.push(new pylint.Linter(this.context.asAbsolutePath("."), this.settings, this.outputChannel));
6869
this.linters.push(new pep8.Linter(this.context.asAbsolutePath("."), this.settings, this.outputChannel));
6970
this.linters.push(new flake8.Linter(this.context.asAbsolutePath("."), this.settings, this.outputChannel));
71+
this.linters.push(new pydocstyle.Linter(this.context.asAbsolutePath("."), this.settings, this.outputChannel));
7072

7173
var disposable = vscode.workspace.onDidChangeTextDocument((e) => {
7274
if (e.document.languageId !== "python" || !this.settings.linting.enabled || !this.settings.linting.lintOnTextChange) {

0 commit comments

Comments
 (0)