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]
@@ -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:
@@ -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