Skip to content

Commit

Permalink
Catch and ignore parser errors for pydocstyle linting (#208)
Browse files Browse the repository at this point in the history
* Catch and ignore parser errors for pydocstyle linting

* Fix pydocstyle empty file

* Fix linting
  • Loading branch information
gatesn authored Dec 22, 2017
1 parent c665291 commit 7a1eca1
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 57 deletions.
2 changes: 1 addition & 1 deletion pyls/config/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def _get_opt(config, key, option, opt_type):
if opt_type == list:
return _parse_list_opt(config.get(key, opt_key))

raise ValueError("Unknown option type: %s", opt_type)
raise ValueError("Unknown option type: %s" % opt_type)


def _parse_list_opt(string):
Expand Down
2 changes: 1 addition & 1 deletion pyls/plugins/mccabe_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def pyls_lint(config, document):
tree = compile(document.source, document.path, "exec", ast.PyCF_ONLY_AST)
except SyntaxError:
# We'll let the other linters point this one out
return
return None

visitor = mccabe.PathGraphingAstVisitor()
visitor.preorder(tree, visitor)
Expand Down
51 changes: 34 additions & 17 deletions pyls/plugins/pydocstyle_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,39 @@ def pyls_lint(document):
document.source, filename, ignore_decorators=ignore_decorators
)

for err in errors:
if err.code not in checked_codes:
continue

lineno = err.definition.start - 1
line = document.lines[lineno]
character = len(line) - len(line.lstrip())
diags.append({
'source': 'pydocstyle',
'code': err.code,
'message': err.message,
'severity': lsp.DiagnosticSeverity.Warning,
'range': {
'start': {'line': lineno, 'character': character},
'end': {'line': lineno, 'character': len(document.lines[lineno])}
}
})
try:
for error in errors:
if error.code not in checked_codes:
continue
diags.append(_parse_diagnostic(document, error))
except pydocstyle.parser.ParseError:
# In the case we cannot parse the Python file, just continue
pass

return diags


def _parse_diagnostic(document, error):
log.info("Got error: %s", error)
lineno = error.definition.start - 1
line = document.lines[0] if document.lines else ""

start_character = len(line) - len(line.lstrip())
end_character = len(line)

return {
'source': 'pydocstyle',
'code': error.code,
'message': error.message,
'severity': lsp.DiagnosticSeverity.Warning,
'range': {
'start': {
'line': lineno,
'character': start_character
},
'end': {
'line': lineno,
'character': end_character
}
}
}
66 changes: 33 additions & 33 deletions pyls/plugins/rope_completion.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Copyright 2017 Palantir Technologies, Inc.
import logging
from pyls.lsp import CompletionItemKind
from pyls import hookimpl

from rope.contrib.codeassist import code_assist, sorted_proposals

from pyls import hookimpl, lsp


log = logging.getLogger(__name__)


Expand Down Expand Up @@ -62,36 +62,36 @@ def _sort_text(definition):
def _kind(d):
""" Return the VSCode type """
MAP = {
'none': CompletionItemKind.Value,
'type': CompletionItemKind.Class,
'tuple': CompletionItemKind.Class,
'dict': CompletionItemKind.Class,
'dictionary': CompletionItemKind.Class,
'function': CompletionItemKind.Function,
'lambda': CompletionItemKind.Function,
'generator': CompletionItemKind.Function,
'class': CompletionItemKind.Class,
'instance': CompletionItemKind.Reference,
'method': CompletionItemKind.Method,
'builtin': CompletionItemKind.Class,
'builtinfunction': CompletionItemKind.Function,
'module': CompletionItemKind.Module,
'file': CompletionItemKind.File,
'xrange': CompletionItemKind.Class,
'slice': CompletionItemKind.Class,
'traceback': CompletionItemKind.Class,
'frame': CompletionItemKind.Class,
'buffer': CompletionItemKind.Class,
'dictproxy': CompletionItemKind.Class,
'funcdef': CompletionItemKind.Function,
'property': CompletionItemKind.Property,
'import': CompletionItemKind.Module,
'keyword': CompletionItemKind.Keyword,
'constant': CompletionItemKind.Variable,
'variable': CompletionItemKind.Variable,
'value': CompletionItemKind.Value,
'param': CompletionItemKind.Variable,
'statement': CompletionItemKind.Keyword,
'none': lsp.CompletionItemKind.Value,
'type': lsp.CompletionItemKind.Class,
'tuple': lsp.CompletionItemKind.Class,
'dict': lsp.CompletionItemKind.Class,
'dictionary': lsp.CompletionItemKind.Class,
'function': lsp.CompletionItemKind.Function,
'lambda': lsp.CompletionItemKind.Function,
'generator': lsp.CompletionItemKind.Function,
'class': lsp.CompletionItemKind.Class,
'instance': lsp.CompletionItemKind.Reference,
'method': lsp.CompletionItemKind.Method,
'builtin': lsp.CompletionItemKind.Class,
'builtinfunction': lsp.CompletionItemKind.Function,
'module': lsp.CompletionItemKind.Module,
'file': lsp.CompletionItemKind.File,
'xrange': lsp.CompletionItemKind.Class,
'slice': lsp.CompletionItemKind.Class,
'traceback': lsp.CompletionItemKind.Class,
'frame': lsp.CompletionItemKind.Class,
'buffer': lsp.CompletionItemKind.Class,
'dictproxy': lsp.CompletionItemKind.Class,
'funcdef': lsp.CompletionItemKind.Function,
'property': lsp.CompletionItemKind.Property,
'import': lsp.CompletionItemKind.Module,
'keyword': lsp.CompletionItemKind.Keyword,
'constant': lsp.CompletionItemKind.Variable,
'variable': lsp.CompletionItemKind.Variable,
'value': lsp.CompletionItemKind.Value,
'param': lsp.CompletionItemKind.Variable,
'statement': lsp.CompletionItemKind.Keyword,
}

return MAP.get(d.type)
4 changes: 3 additions & 1 deletion pyls/plugins/symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ def _container(definition):
if parent.parent():
return parent.name
except: # pylint: disable=bare-except
pass
return None

return None


def _range(definition):
Expand Down
2 changes: 2 additions & 0 deletions pyls/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,5 @@ def _content_length(line):
return int(value)
except ValueError:
raise ValueError("Invalid Content-Length header: {}".format(value))

return None
28 changes: 24 additions & 4 deletions test/plugins/test_pydocstyle_lint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copyright 2017 Palantir Technologies, Inc.
from pyls import uris
from pyls import lsp, uris
from pyls.workspace import Document
from pyls.plugins import pydocstyle_lint

Expand All @@ -20,7 +20,27 @@ def test_pydocstyle():
assert all([d['source'] == 'pydocstyle' for d in diags])

# One we're expecting is:
msg = 'D100: Missing docstring in public module'
unused_import = [d for d in diags if d['message'] == msg][0]
assert diags[0] == {
'code': 'D100',
'message': 'D100: Missing docstring in public module',
'severity': lsp.DiagnosticSeverity.Warning,
'range': {
'start': {'line': 0, 'character': 0},
'end': {'line': 0, 'character': 11},
},
'source': 'pydocstyle'
}


def test_pydocstyle_empty_source():
doc = Document(DOC_URI, "")
diags = pydocstyle_lint.pyls_lint(doc)
assert diags[0]['message'] == 'D100: Missing docstring in public module'
assert len(diags) == 1


assert unused_import['range']['start'] == {'line': 0, 'character': 0}
def test_pydocstyle_invalid_source():
doc = Document(DOC_URI, "bad syntax")
diags = pydocstyle_lint.pyls_lint(doc)
# We're unable to parse the file, so can't get any pydocstyle diagnostics
assert not diags

0 comments on commit 7a1eca1

Please sign in to comment.