-
Notifications
You must be signed in to change notification settings - Fork 285
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
161 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# Copyright 2019 Palantir Technologies, Inc. | ||
"""Linter pluging for flake8""" | ||
import logging | ||
from flake8.api import legacy as flake8 | ||
from pyls import hookimpl, lsp | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
@hookimpl | ||
def pyls_settings(): | ||
# Default flake8 to disabled | ||
return {'plugins': {'flake8': {'enabled': False}}} | ||
|
||
|
||
@hookimpl | ||
def pyls_lint(config, document): | ||
settings = config.plugin_settings('flake8') | ||
log.debug("Got flake8 settings: %s", settings) | ||
|
||
opts = { | ||
'exclude': settings.get('exclude'), | ||
'filename': settings.get('filename'), | ||
'hang_closing': settings.get('hangClosing'), | ||
'ignore': settings.get('ignore'), | ||
'max_line_length': settings.get('maxLineLength'), | ||
'select': settings.get('select'), | ||
} | ||
|
||
# Build the flake8 checker and use it to generate a report from the document | ||
kwargs = {k: v for k, v in opts.items() if v} | ||
style_guide = flake8.get_style_guide(quiet=4, verbose=0, **kwargs) | ||
report = style_guide.check_files([document.path]) | ||
|
||
return parse_report(document, report) | ||
|
||
|
||
def parse_report(document, report): | ||
""" | ||
Build a diagnostics from a report, it should extract every result and format | ||
it into a dict that looks like this: | ||
{ | ||
'source': 'flake8', | ||
'code': code, # 'E501' | ||
'range': { | ||
'start': { | ||
'line': start_line, | ||
'character': start_column, | ||
}, | ||
'end': { | ||
'line': end_line, | ||
'character': end_column, | ||
}, | ||
}, | ||
'message': msg, | ||
'severity': lsp.DiagnosticSeverity.*, | ||
} | ||
Args: | ||
document: The document to be linted. | ||
report: A Report object returned by checking the document. | ||
Returns: | ||
A list of dictionaries. | ||
""" | ||
|
||
file_checkers = report._application.file_checker_manager.checkers | ||
# No file have been checked | ||
if not file_checkers: | ||
return [] | ||
# There should be only a filechecker since we are parsing using a path and not a pattern | ||
if len(file_checkers) > 1: | ||
log.error("Flake8 parsed more than a file for '%s'", document.path) | ||
|
||
diagnostics = [] | ||
file_checker = file_checkers[0] | ||
for error in file_checker.results: | ||
code, line, character, msg, physical_line = error | ||
diagnostics.append( | ||
{ | ||
'source': 'flake8', | ||
'code': code, | ||
'range': { | ||
'start': { | ||
'line': line, | ||
'character': character | ||
}, | ||
'end': { | ||
'line': line, | ||
# no way to determine the column | ||
'character': len(physical_line) | ||
} | ||
}, | ||
'message': msg, | ||
# no way to determine the severity using the legacy api | ||
'severity': lsp.DiagnosticSeverity.Warning, | ||
} | ||
) | ||
|
||
return diagnostics |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Copyright 2019 Palantir Technologies, Inc. | ||
import tempfile | ||
import os | ||
from pyls import lsp, uris | ||
from pyls.plugins import flake8_lint | ||
from pyls.workspace import Document | ||
|
||
DOC_URI = uris.from_fs_path(__file__) | ||
DOC = """import pyls | ||
t = "TEST" | ||
def using_const(): | ||
\ta = 8 + 9 | ||
\treturn t | ||
""" | ||
|
||
|
||
def temp_document(doc_text): | ||
temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False) | ||
name = temp_file.name | ||
temp_file.write(doc_text) | ||
temp_file.close() | ||
doc = Document(uris.from_fs_path(name)) | ||
|
||
return name, doc | ||
|
||
|
||
def test_flake8_no_checked_file(config): | ||
# A bad uri or a non-saved file may cause the flake8 linter to do nothing. | ||
# In this situtation, the linter will return an empty list. | ||
|
||
doc = Document('', DOC) | ||
diags = flake8_lint.pyls_lint(config, doc) | ||
assert diags == [] | ||
|
||
|
||
def test_flake8_lint(config): | ||
try: | ||
name, doc = temp_document(DOC) | ||
diags = flake8_lint.pyls_lint(config, doc) | ||
msg = 'local variable \'a\' is assigned to but never used' | ||
unused_var = [d for d in diags if d['message'] == msg][0] | ||
|
||
assert unused_var['source'] == 'flake8' | ||
assert unused_var['code'] == 'F841' | ||
assert unused_var['range']['start'] == {'line': 6, 'character': 1} | ||
assert unused_var['range']['end'] == {'line': 6, 'character': 11} | ||
assert unused_var['severity'] == lsp.DiagnosticSeverity.Warning | ||
|
||
finally: | ||
os.remove(name) |