Replace linter (#37)

This commit is contained in:
Regen
2021-03-28 22:23:57 +09:00
committed by GitHub
parent 6e839f7675
commit 4d120a6a98
17 changed files with 563 additions and 578 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
poetry.lock linguist-generated=true

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python: [3.6, 3.7, 3.8]
python: [3.6, 3.7, 3.8, 3.9]
os: [ubuntu-18.04, windows-2016]
steps:
- uses: actions/checkout@v2

129
.gitignore vendored
View File

@@ -1,133 +1,4 @@
### https://raw.github.com/github/gitignore/cb0c6ef7ac68f2300409ee85501d9ad432cb4c7e/Python.gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

View File

@@ -1,2 +0,0 @@
[style]
based_on_style = pep8

View File

@@ -1,6 +0,0 @@
[mypy]
ignore_missing_imports = True
allow_redefinition = True
[mypy-re.Scanner]
ignore_errors = True

754
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -23,14 +23,10 @@ pygls = "^0.8.1"
pyparsing = "^2.4"
[tool.poetry.dev-dependencies]
flake8 = "^3.7"
mypy = "^0.740.0"
pytest = "^5.2"
pytest = "^6.2"
pytest-datadir = "^1.3"
tox = "^3.14"
isort = "^4.3"
pytest-cov = "^2.8"
black = "^19.10b0"
pytest-cov = "^2.11"
pysen = {version = "^0.9", extras = ["lint"]}
[tool.poetry.scripts]
cmake-format = "cmake_language_server.formatter:main"
@@ -39,3 +35,18 @@ cmake-language-server = "cmake_language_server.server:main"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.pysen]
version = "0.9"
[tool.pysen.lint]
enable_black = true
enable_flake8 = true
enable_isort = true
enable_mypy = true
mypy_preset = "strict"
line_length = 88
py_version = "py36"
[[tool.pysen.lint.mypy_targets]]
paths = ["."]

View File

@@ -25,7 +25,7 @@ class API(object):
_uuid: uuid.UUID
_builtin_commands: Dict[str, str]
_builtin_variables: Dict[str, str]
_builtin_variable_template: Dict[Pattern, str]
_builtin_variable_template: Dict[Pattern[str], str]
_builtin_modules: Dict[str, str]
_targets: List[str]
_cached_variables: Dict[str, str]
@@ -45,7 +45,7 @@ class API(object):
self._generated_list_parsed = False
def query(self) -> bool:
""" Use CMake's file API to get JSON information about the build tree
"""Use CMake's file API to get JSON information about the build tree
Generates a JSON request file for the current build tree and runs
CMake on the build tree. Deletes the request file immediately
@@ -83,7 +83,7 @@ class API(object):
return True
def read_reply(self) -> bool:
""" Reads the CMake file API reply file and updates internal state
"""Reads the CMake file API reply file and updates internal state
Reads the result of the previous query file and updates
the targets, the cache entries and the cmake files.
@@ -112,13 +112,13 @@ class API(object):
return True
def _read_codemodel(self, codemodelpath: Path):
def _read_codemodel(self, codemodelpath: Path) -> None:
with (codemodelpath).open() as fp:
codemodel = json.load(fp)
config = codemodel["configurations"][0]
self._targets[:] = [x["name"] for x in config["targets"]]
def _read_cache(self, cachepath: Path):
def _read_cache(self, cachepath: Path) -> None:
with cachepath.open() as fp:
cache = json.load(fp)
self._cached_variables.clear()
@@ -134,7 +134,7 @@ class API(object):
doc.append(f"`{value}`")
self._cached_variables[name] = "\n\n".join(doc)
def _read_cmake_files(self, jsonpath: Path):
def _read_cmake_files(self, jsonpath: Path) -> None:
"""inspect CMake list files that are used during build generation"""
if not self._builtin_variables or self._generated_list_parsed:
@@ -214,7 +214,7 @@ endforeach()
self._parse_modules()
def _parse_commands(self) -> None:
""" Load docs for builtin cmake functions
"""Load docs for builtin cmake functions
Loads the documentation for builtin cmake functions from the result
of `$ cmake --help-commands`.
@@ -247,7 +247,7 @@ endforeach()
self._builtin_commands[command] = "```cmake\n" + signature + "\n```"
def _parse_variables(self) -> None:
""" Load docs for builtin cmake variables
"""Load docs for builtin cmake variables
Loads the documentation for builtin cmake variables from
the result of `$ cmake --help-variables`.
@@ -286,7 +286,7 @@ endforeach()
self._builtin_variables[variable] = doc
def _parse_modules(self) -> None:
""" Loads docs for all modules in the cmake distribution
"""Loads docs for all modules in the cmake distribution
Loads the documentation for cmake modules included in the
distribution from the result of `$ cmake --help-modules`.
@@ -316,7 +316,7 @@ endforeach()
module = match.group("module")
header = match.group("header")
doc = _tidy_doc(match.group("doc"))
if header is not None and header != "Overview":
if header != "Overview":
doc = ""
self._builtin_modules[module] = doc

View File

@@ -1,4 +1,4 @@
from typing import List
from typing import List, Optional
from .parser import TokenList
@@ -7,7 +7,7 @@ class Formatter(object):
indent: str
lower_identifier: bool
def __init__(self, indent=" ", lower_identifier=True):
def __init__(self, indent: str = " ", lower_identifier: bool = True):
self.indent = indent
self.lower_identifier = lower_identifier
@@ -94,7 +94,7 @@ class Formatter(object):
return ret
def main(args: List[str] = None):
def main(argss: Optional[List[str]] = None) -> None:
import sys
from argparse import ArgumentParser
from difflib import unified_diff
@@ -117,7 +117,7 @@ def main(args: List[str] = None):
"--version", action="version", version=f"%(prog)s {__version__}"
)
args = parser.parse_args(args)
args = parser.parse_args(argss)
if not args.lists and args.inplace:
print("error: cannot use -i when no arguments are specified.", file=sys.stderr)

View File

@@ -10,7 +10,7 @@ TokenList = List[TokenType]
class ListParser(object):
_parser: pp.ParserElement
def __init__(self):
def __init__(self) -> None:
newline = "\n"
space_plus = pp.Regex("[ \t]+")
space_star = pp.Optional(space_plus)
@@ -20,7 +20,7 @@ class ListParser(object):
bracket_content = pp.Forward()
def action_bracket_open(tokens: pp.ParseResults):
def action_bracket_open(tokens: pp.ParseResults) -> None:
nonlocal bracket_content
marker = "]" + "=" * (len(tokens[0]) - 2) + "]"
bracket_content <<= pp.SkipTo(marker, include=True)

View File

@@ -1,7 +1,7 @@
import logging
import re
from pathlib import Path
from typing import List, Optional, Tuple
from typing import Any, Callable, List, Optional, Tuple
from pygls.features import (
COMPLETION,
@@ -36,18 +36,18 @@ from .parser import ListParser
logger = logging.getLogger(__name__)
class CMakeLanguageServer(LanguageServer):
class CMakeLanguageServer(LanguageServer): # type: ignore
_parser: ListParser
_api: API
_api: Optional[API]
def __init__(self, *args):
def __init__(self, *args: Any) -> None:
super().__init__(*args)
self._parser = ListParser()
self._api = None
@self.feature(INITIALIZE)
def initialize(params: InitializeParams):
def initialize(params: InitializeParams) -> None:
opts = params.initializationOptions
cmake = getattr(opts, "cmakeExecutable", "cmake")
@@ -60,7 +60,9 @@ class CMakeLanguageServer(LanguageServer):
trigger_characters = ["{", "("]
@self.feature(COMPLETION, trigger_characters=trigger_characters)
def completions(params: CompletionParams):
def completions(params: CompletionParams) -> CompletionList:
assert self._api is not None
if (
hasattr(params, "context")
and params.context.triggerKind == CompletionTriggerKind.TriggerCharacter
@@ -143,7 +145,7 @@ class CMakeLanguageServer(LanguageServer):
return CompletionList(False, items)
@self.feature(FORMATTING)
def formatting(params: DocumentFormattingParams):
def formatting(params: DocumentFormattingParams) -> Optional[List[TextEdit]]:
doc = self.workspace.get_document(params.textDocument.uri)
content = doc.source
tokens, remain = self._parser.parse(content)
@@ -156,16 +158,19 @@ class CMakeLanguageServer(LanguageServer):
return [TextEdit(Range(Position(0, 0), Position(lines + 1, 0)), formatted)]
@self.feature(HOVER)
def hover(params: TextDocumentPositionParams):
def hover(params: TextDocumentPositionParams) -> Optional[Hover]:
assert self._api is not None
api = self._api
word = self._cursor_word(params.textDocument.uri, params.position, True)
if not word:
return None
candidates = [
lambda x: self._api.get_command_doc(x.lower()),
lambda x: self._api.get_variable_doc(x),
lambda x: self._api.get_module_doc(x, False),
lambda x: self._api.get_module_doc(x, True),
candidates: List[Callable[[str], Optional[str]]] = [
lambda x: api.get_command_doc(x.lower()),
lambda x: api.get_variable_doc(x),
lambda x: api.get_module_doc(x, False),
lambda x: api.get_module_doc(x, True),
]
for c in candidates:
doc = c(word[0])
@@ -177,7 +182,9 @@ class CMakeLanguageServer(LanguageServer):
@self.thread()
@self.feature(TEXT_DOCUMENT_DID_SAVE, includeText=False)
@self.feature(INITIALIZED)
def run_cmake(*args):
def run_cmake(*args: Any) -> None:
assert self._api is not None
if self._api.query():
self._api.read_reply()
@@ -192,7 +199,7 @@ class CMakeLanguageServer(LanguageServer):
doc = self.workspace.get_document(uri)
content = doc.source
line = content.split("\n")[position.line]
return line
return str(line)
def _cursor_word(
self, uri: str, position: Position, include_all: bool = True
@@ -212,7 +219,7 @@ class CMakeLanguageServer(LanguageServer):
return None
def main(args=None):
def main() -> None:
from argparse import ArgumentParser
from . import __version__
@@ -221,7 +228,7 @@ def main(args=None):
parser.add_argument(
"--version", action="version", version=f"%(prog)s {__version__}"
)
args = parser.parse_args(args)
parser.parse_args()
logging.basicConfig(level=logging.INFO)
logging.getLogger("pygls").setLevel(logging.WARNING)

View File

@@ -2,18 +2,19 @@ import asyncio
import logging
import os
import pprint
from pathlib import Path
from subprocess import PIPE, run
from threading import Thread
from typing import Iterable, Tuple
import pytest
from cmake_language_server.server import CMakeLanguageServer
from pygls import features
from pygls.server import LanguageServer
from cmake_language_server.server import CMakeLanguageServer
@pytest.fixture()
def cmake_build(shared_datadir):
def cmake_build(shared_datadir: Path) -> Iterable[Path]:
source = shared_datadir / "cmake"
build = source / "build"
build.mkdir()
@@ -33,11 +34,11 @@ def cmake_build(shared_datadir):
@pytest.fixture()
def client_server():
def client_server() -> Iterable[Tuple[LanguageServer, CMakeLanguageServer]]:
c2s_r, c2s_w = os.pipe()
s2c_r, s2c_w = os.pipe()
def start(ls: LanguageServer, fdr, fdw):
def start(ls: LanguageServer, fdr: int, fdw: int) -> None:
# TODO: better patch is needed
# disable `close()` to avoid error messages
close = ls.loop.close

View File

@@ -1,9 +1,10 @@
import subprocess
from pathlib import Path
from cmake_language_server.api import API
def test_query_with_cache(cmake_build):
def test_query_with_cache(cmake_build: Path) -> None:
api = API("cmake", cmake_build)
assert api.query()
@@ -14,14 +15,14 @@ def test_query_with_cache(cmake_build):
assert reply.exists()
def test_query_without_cache(cmake_build):
def test_query_without_cache(cmake_build: Path) -> None:
api = API("cmake", cmake_build)
(cmake_build / "CMakeCache.txt").unlink()
assert not api.query()
def test_read_variable(cmake_build):
def test_read_variable(cmake_build: Path) -> None:
api = API("cmake", cmake_build)
assert api.query()
assert api.read_reply()
@@ -29,7 +30,7 @@ def test_read_variable(cmake_build):
assert api.get_variable_doc("testproject_BINARY_DIR")
def test_read_cmake_files(cmake_build):
def test_read_cmake_files(cmake_build: Path) -> None:
api = API("cmake", cmake_build)
api.parse_doc()
assert api.query()
@@ -48,7 +49,7 @@ def test_read_cmake_files(cmake_build):
raise RuntimeError("Unexpected system")
def test_parse_commands(cmake_build):
def test_parse_commands(cmake_build: Path) -> None:
api = API("cmake", cmake_build)
api.parse_doc()
@@ -67,7 +68,7 @@ def test_parse_commands(cmake_build):
assert api.get_command_doc("not_existing_command") is None
def test_parse_variables(cmake_build):
def test_parse_variables(cmake_build: Path) -> None:
api = API("cmake", cmake_build)
api.parse_doc()
@@ -88,7 +89,7 @@ def test_parse_variables(cmake_build):
assert api.get_variable_doc("not_existing_variable") is None
def test_parse_modules(cmake_build):
def test_parse_modules(cmake_build: Path) -> None:
api = API("cmake", cmake_build)
api.parse_doc()

View File

@@ -1,13 +1,16 @@
import sys
from contextlib import contextmanager
from io import StringIO
from pathlib import Path
from typing import Callable, Iterator
from cmake_language_server.formatter import Formatter, main
from cmake_language_server.parser import ListParser
from pytest import CaptureFixture
def make_formatter_test(liststr: str, expect: str):
def test():
def make_formatter_test(liststr: str, expect: str) -> Callable[[], None]:
def test() -> None:
tokens, remain = ListParser().parse(liststr)
actual = Formatter().format(tokens)
assert actual == expect
@@ -88,14 +91,14 @@ endif()
@contextmanager
def mock_stdin(buf: str):
def mock_stdin(buf: str) -> Iterator[None]:
stdin = sys.stdin
sys.stdin = StringIO(buf)
yield
sys.stdin = stdin
def test_main_stdin(capsys):
def test_main_stdin(capsys: CaptureFixture[str]) -> None:
with mock_stdin(" a()"):
main([])
captured = capsys.readouterr()
@@ -103,7 +106,7 @@ def test_main_stdin(capsys):
assert captured.err == ""
def test_main_stdin_diff(capsys):
def test_main_stdin_diff(capsys: CaptureFixture[str]) -> None:
with mock_stdin(" a()"):
main(["-d"])
captured = capsys.readouterr()
@@ -112,7 +115,7 @@ def test_main_stdin_diff(capsys):
assert captured.err == ""
def test_main_file_1(capsys, tmp_path):
def test_main_file_1(capsys: CaptureFixture[str], tmp_path: Path) -> None:
testfile1 = tmp_path / "list1.cmake"
with testfile1.open("w") as fp:
fp.write(" a()")
@@ -123,7 +126,7 @@ def test_main_file_1(capsys, tmp_path):
assert captured.err == ""
def test_main_file_2(capsys, tmp_path):
def test_main_file_2(capsys: CaptureFixture[str], tmp_path: Path) -> None:
testfile1 = tmp_path / "list1.cmake"
with testfile1.open("w") as fp:
fp.write(" a()")
@@ -137,7 +140,7 @@ def test_main_file_2(capsys, tmp_path):
assert captured.err == ""
def test_main_inplace(capsys, tmp_path):
def test_main_inplace(capsys: CaptureFixture[str], tmp_path: Path) -> None:
testfile1 = tmp_path / "list1.cmake"
with testfile1.open("w") as fp:
fp.write(" a()")
@@ -152,7 +155,7 @@ def test_main_inplace(capsys, tmp_path):
assert content == "a()\n"
def test_main_diff(capsys, tmp_path):
def test_main_diff(capsys: CaptureFixture[str], tmp_path: Path) -> None:
testfile1 = tmp_path / "list1.cmake"
with testfile1.open("w") as fp:
fp.write(" a()")

View File

@@ -1,12 +1,12 @@
from typing import List
from typing import Callable, List
from cmake_language_server.parser import ListParser, TokenType
def make_parser_test(
liststr: str, expect_token: List[TokenType], expect_remain: str = ""
):
def test():
) -> Callable[[], None]:
def test() -> None:
actual_token, actual_remain = ListParser().parse(liststr)
assert actual_token == expect_token
assert actual_remain == expect_remain

View File

@@ -1,7 +1,8 @@
from concurrent import futures
from pathlib import Path
from typing import Optional
from typing import Optional, Tuple
from cmake_language_server.server import CMakeLanguageServer
from pygls.features import (
COMPLETION,
FORMATTING,
@@ -12,6 +13,7 @@ from pygls.features import (
from pygls.server import LanguageServer
from pygls.types import (
CompletionContext,
CompletionList,
CompletionParams,
CompletionTriggerKind,
DidOpenTextDocumentParams,
@@ -27,7 +29,7 @@ from pygls.types import (
CALL_TIMEOUT = 2
def _init(client: LanguageServer, root: Path):
def _init(client: LanguageServer, root: Path) -> None:
retry = 3
while retry > 0:
try:
@@ -43,7 +45,7 @@ def _init(client: LanguageServer, root: Path):
break
def _open(client: LanguageServer, path: Path, text: Optional[str] = None):
def _open(client: LanguageServer, path: Path, text: Optional[str] = None) -> None:
if text is None:
with open(path) as fp:
text = fp.read()
@@ -55,8 +57,11 @@ def _open(client: LanguageServer, path: Path, text: Optional[str] = None):
def _test_completion(
client_server, datadir, content: str, context: Optional[CompletionContext]
):
client_server: Tuple[LanguageServer, CMakeLanguageServer],
datadir: Path,
content: str,
context: Optional[CompletionContext],
) -> CompletionList:
client, server = client_server
_init(client, datadir)
path = datadir / "CMakeLists.txt"
@@ -70,7 +75,9 @@ def _test_completion(
return client.lsp.send_request(COMPLETION, params).result(timeout=CALL_TIMEOUT)
def test_initialize(client_server, datadir):
def test_initialize(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
client, server = client_server
assert server._api is None
@@ -78,7 +85,9 @@ def test_initialize(client_server, datadir):
assert server._api is not None
def test_completions_invoked(client_server, datadir):
def test_completions_invoked(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
response = _test_completion(
client_server,
datadir,
@@ -90,14 +99,18 @@ def test_completions_invoked(client_server, datadir):
assert "<PROJECT-NAME>" in item.documentation
def test_completions_nocontext(client_server, datadir):
def test_completions_nocontext(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
response = _test_completion(client_server, datadir, "projec", None)
item = next(filter(lambda x: x.label == "project", response.items), None)
assert item is not None
assert "<PROJECT-NAME>" in item.documentation
def test_completions_triggercharacter_variable(client_server, datadir):
def test_completions_triggercharacter_variable(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
response = _test_completion(
client_server,
datadir,
@@ -110,7 +123,9 @@ def test_completions_triggercharacter_variable(client_server, datadir):
assert response == response_nocontext
def test_completions_triggercharacter_module(client_server, datadir):
def test_completions_triggercharacter_module(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
response = _test_completion(
client_server,
datadir,
@@ -123,7 +138,9 @@ def test_completions_triggercharacter_module(client_server, datadir):
assert response == response_nocontext
def test_completions_triggercharacter_package(client_server, datadir):
def test_completions_triggercharacter_package(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
response = _test_completion(
client_server,
datadir,
@@ -136,7 +153,9 @@ def test_completions_triggercharacter_package(client_server, datadir):
assert response == response_nocontext
def test_formatting(client_server, datadir):
def test_formatting(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
client, server = client_server
_init(client, datadir)
path = datadir / "CMakeLists.txt"
@@ -150,7 +169,9 @@ def test_formatting(client_server, datadir):
assert response[0].newText == "a(b c)\n"
def test_hover(client_server, datadir):
def test_hover(
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
) -> None:
client, server = client_server
_init(client, datadir)
path = datadir / "CMakeLists.txt"

27
tox.ini
View File

@@ -1,25 +1,15 @@
[isort]
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
line_length = 88
[flake8]
max-line-length = 88
extend-ignore = E203, W503
[tox]
isolated_build = True
skipsdist = True
envlist = py36, py37, py38, lint
envlist = py36, py37, py38, py39, lint
allowlist_externals = git
[gh-actions]
python =
3.6: py36
3.7: py37, lint
3.8: py38
3.7: py37
3.8: py38, lint
3.9: py39
[testenv]
whitelist_externals = poetry
@@ -32,7 +22,6 @@ commands =
[testenv:lint]
commands =
poetry run isort -c -rc src tests
poetry run black --diff src tests
poetry run flake8 src tests
poetry run mypy src tests
poetry run pysen run format
git diff --exit-code --ignore-submodules
poetry run pysen run lint