1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
# Copyright 2018 Google LLC.
import contextlib
import os
import tempfile
from test import py2_only, py3_only, IS_PY3
from pyls import lsp, uris
from pyls.workspace import Document
from pyls.plugins import pylint_lint
DOC_URI = uris.from_fs_path(__file__)
DOC = """import sys
def hello():
\tpass
import json
"""
DOC_SYNTAX_ERR = """def hello()
pass
"""
@contextlib.contextmanager
def temp_document(doc_text, workspace):
try:
temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
name = temp_file.name
temp_file.write(doc_text)
temp_file.close()
yield Document(uris.from_fs_path(name), workspace)
finally:
os.remove(name)
def write_temp_doc(document, contents):
with open(document.path, 'w') as temp_file:
temp_file.write(contents)
def test_pylint(config, workspace):
with temp_document(DOC, workspace) as doc:
diags = pylint_lint.pyls_lint(config, doc, True)
msg = '[unused-import] Unused import sys'
unused_import = [d for d in diags if d['message'] == msg][0]
assert unused_import['range']['start'] == {'line': 0, 'character': 0}
assert unused_import['severity'] == lsp.DiagnosticSeverity.Warning
if IS_PY3:
# test running pylint in stdin
config.plugin_settings('pylint')['executable'] = 'pylint'
diags = pylint_lint.pyls_lint(config, doc, True)
msg = 'Unused import sys (unused-import)'
unused_import = [d for d in diags if d['message'] == msg][0]
assert unused_import['range']['start'] == {
'line': 0,
'character': 0,
}
assert unused_import['severity'] == lsp.DiagnosticSeverity.Warning
@py3_only
def test_syntax_error_pylint_py3(config, workspace):
with temp_document(DOC_SYNTAX_ERR, workspace) as doc:
diag = pylint_lint.pyls_lint(config, doc, True)[0]
assert diag['message'].startswith('[syntax-error] invalid syntax')
# Pylint doesn't give column numbers for invalid syntax.
assert diag['range']['start'] == {'line': 0, 'character': 12}
assert diag['severity'] == lsp.DiagnosticSeverity.Error
# test running pylint in stdin
config.plugin_settings('pylint')['executable'] = 'pylint'
diag = pylint_lint.pyls_lint(config, doc, True)[0]
assert diag['message'].startswith('invalid syntax')
# Pylint doesn't give column numbers for invalid syntax.
assert diag['range']['start'] == {'line': 0, 'character': 12}
assert diag['severity'] == lsp.DiagnosticSeverity.Error
@py2_only
def test_syntax_error_pylint_py2(config, workspace):
with temp_document(DOC_SYNTAX_ERR, workspace) as doc:
diag = pylint_lint.pyls_lint(config, doc, True)[0]
assert diag['message'].startswith('[syntax-error] invalid syntax')
# Pylint doesn't give column numbers for invalid syntax.
assert diag['range']['start'] == {'line': 0, 'character': 0}
assert diag['severity'] == lsp.DiagnosticSeverity.Error
def test_lint_free_pylint(config, workspace):
# Can't use temp_document because it might give us a file that doesn't
# match pylint's naming requirements. We should be keeping this file clean
# though, so it works for a test of an empty lint.
assert not pylint_lint.pyls_lint(
config, Document(uris.from_fs_path(__file__), workspace), True)
def test_lint_caching(workspace):
# Pylint can only operate on files, not in-memory contents. We cache the
# diagnostics after a run so we can continue displaying them until the file
# is saved again.
#
# We use PylintLinter.lint directly here rather than pyls_lint so we can
# pass --disable=invalid-name to pylint, since we want a temporary file but
# need to ensure that pylint doesn't give us invalid-name when our temp
# file has capital letters in its name.
flags = '--disable=invalid-name'
with temp_document(DOC, workspace) as doc:
# Start with a file with errors.
diags = pylint_lint.PylintLinter.lint(doc, True, flags)
assert diags
# Fix lint errors and write the changes to disk. Run the linter in the
# in-memory mode to check the cached diagnostic behavior.
write_temp_doc(doc, '')
assert pylint_lint.PylintLinter.lint(doc, False, flags) == diags
# Now check the on-disk behavior.
assert not pylint_lint.PylintLinter.lint(doc, True, flags)
# Make sure the cache was properly cleared.
assert not pylint_lint.PylintLinter.lint(doc, False, flags)
def test_per_file_caching(config, workspace):
# Ensure that diagnostics are cached per-file.
with temp_document(DOC, workspace) as doc:
assert pylint_lint.pyls_lint(config, doc, True)
assert not pylint_lint.pyls_lint(
config, Document(uris.from_fs_path(__file__), workspace), False)
|