Skip to content

Commit

Permalink
lsp-devtools: Use hatch for linting and testing
Browse files Browse the repository at this point in the history
  • Loading branch information
alcarney committed May 22, 2024
1 parent 6fe86ff commit 980113b
Show file tree
Hide file tree
Showing 19 changed files with 692 additions and 75 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/lsp-devtools-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,11 @@ jobs:
- run: |
python --version
python -m pip install --upgrade pip
python -m pip install --upgrade tox
python -m pip install --upgrade hatch
name: Setup Environment
- run: |
cd lib/lsp-devtools
version=$(echo ${{ matrix.python-version }} | tr -d .)
python -m tox run -f "py${version}"
hatch test -i py=${{ matrix.python-version }}
shell: bash
name: Run Tests
23 changes: 13 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ repos:
rev: 24.4.2
hooks:
- id: black
name: black (pytest-lsp)
files: 'lib/pytest-lsp/pytest_lsp/.*\.py'

- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
hooks:
- id: flake8
name: flake8 (lsp-devtools)
args: [--config=lib/lsp-devtools/setup.cfg]
files: 'lib/lsp-devtools/lsp_devtools/.*\.py'

- id: flake8
name: flake8 (pytest-lsp)
args: [--config=lib/pytest-lsp/setup.cfg]
Expand All @@ -30,16 +27,22 @@ repos:
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
name: isort (lsp-devtools)
args: [--settings-file, lib/lsp-devtools/pyproject.toml]
files: 'lib/lsp-devtools/lsp_devtools/.*\.py'

- id: isort
name: isort (pytest-lsp)
args: [--settings-file, lib/pytest-lsp/pyproject.toml]
files: 'lib/pytest-lsp/pytest_lsp/.*\.py'


- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
args: [--fix]
files: 'lib/lsp-devtools/.*\.py'

- id: ruff-format
files: 'lib/lsp-devtools/.*\.py'

- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.10.0'
hooks:
Expand Down
7 changes: 7 additions & 0 deletions lib/lsp-devtools/hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ include = ["lsp_devtools", "tests", "CHANGES.md"]

[build.targets.wheel]
packages = ["lsp_devtools"]

[envs.hatch-test]
extra-dependencies = ["pytest-asyncio"]

[envs.hatch-static-analysis]
config-path = "ruff_defaults.toml"
dependencies = ["ruff==0.4.4"]
11 changes: 7 additions & 4 deletions lib/lsp-devtools/lsp_devtools/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sys
import typing
from datetime import datetime
from datetime import timezone
from functools import partial
from uuid import uuid4

Expand All @@ -26,6 +27,7 @@

MessageHandler = Callable[[bytes], Union[None, Coroutine[Any, Any, None]]]

UTC = timezone.utc
logger = logging.getLogger("lsp_devtools.agent")


Expand Down Expand Up @@ -157,8 +159,8 @@ async def start(self):
self.reader, self.writer = await get_streams(self.stdin, self.stdout)

# Keep mypy happy
assert self.server.stdin
assert self.server.stdout
if self.server.stdin is None or self.server.stdout is None:
raise RuntimeError("Unable to find server I/O streams")

# Connect stdin to the subprocess' stdin
client_to_server = asyncio.create_task(
Expand Down Expand Up @@ -196,10 +198,11 @@ async def forward_message(

# Include some additional metadata before passing it onto the devtool.
# TODO: How do we make sure we choose the same encoding as `message`?
now = datetime.now(tz=UTC).isoformat()
fields = [
f"Message-Source: {source}\r\n".encode(),
f"Message-Session: {self.session_id}\r\n".encode(),
f"Message-Timestamp: {datetime.now().isoformat()}\r\n".encode(),
f"Message-Timestamp: {now}\r\n".encode(),
message,
]

Expand All @@ -224,7 +227,7 @@ async def stop(self):
self.server.kill()

args = {}
if sys.version_info.minor > 8:
if sys.version_info >= (3, 9):
args["msg"] = "lsp-devtools agent is stopping."

# Cancel the tasks connecting client to server
Expand Down
6 changes: 4 additions & 2 deletions lib/lsp-devtools/lsp_devtools/client/lsp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import importlib.metadata
import json
from datetime import datetime
from datetime import timezone
from typing import Optional
from uuid import uuid4

Expand All @@ -10,6 +11,7 @@

from lsp_devtools.agent import logger

UTC = timezone.utc
VERSION = importlib.metadata.version("lsp-devtools")


Expand All @@ -27,7 +29,7 @@ def _procedure_handler(self, message):
extra={
"Message-Source": "server",
"Message-Session": self.session_id,
"Message-Timestamp": datetime.now().isoformat(),
"Message-Timestamp": datetime.now(tz=UTC).isoformat(),
},
)
return super()._procedure_handler(message)
Expand All @@ -39,7 +41,7 @@ def _send_data(self, data):
extra={
"Message-Source": "client",
"Message-Session": self.session_id,
"Message-Timestamp": datetime.now().isoformat(),
"Message-Timestamp": datetime.now(tz=UTC).isoformat(),
},
)
return super()._send_data(data)
Expand Down
14 changes: 7 additions & 7 deletions lib/lsp-devtools/lsp_devtools/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

from lsp_devtools.handlers import LspMessage

if sys.version_info.minor < 9:
if sys.version_info < (3, 9):
import importlib_resources as resources
else:
import importlib.resources as resources # type: ignore[no-redef]
from importlib import resources # type: ignore[no-redef]


class Database:
Expand Down Expand Up @@ -64,11 +64,11 @@ async def cursor(self):
async def add_message(self, session: str, timestamp: str, source: str, rpc: dict):
"""Add a new rpc message to the database."""

msg_id = rpc.get("id", None)
method = rpc.get("method", None)
params = rpc.get("params", None)
result = rpc.get("result", None)
error = rpc.get("error", None)
msg_id = rpc.get("id")
method = rpc.get("method")
params = rpc.get("params")
result = rpc.get("result")
error = rpc.get("error")

async with self.cursor() as cursor:
await cursor.execute(
Expand Down
4 changes: 2 additions & 2 deletions lib/lsp-devtools/lsp_devtools/handlers/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
from lsp_devtools.handlers import LspHandler
from lsp_devtools.handlers import LspMessage

if sys.version_info.minor < 9:
if sys.version_info < (3, 9):
import importlib_resources as resources
else:
import importlib.resources as resources # type: ignore[no-redef]
from importlib import resources # type: ignore[no-redef]


class SqlHandler(LspHandler):
Expand Down
16 changes: 8 additions & 8 deletions lib/lsp-devtools/lsp_devtools/record/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,44 +207,44 @@ def start_recording(args, extra: List[str]):
def setup_filter_args(cmd: argparse.ArgumentParser):
"""Add arguments that can be used to filter messages."""

filter = cmd.add_argument_group(
filter_ = cmd.add_argument_group(
title="filter options",
description=(
"select which messages to record, mutliple options will be ANDed together. "
"Does not apply to raw message capture"
),
)
filter.add_argument(
filter_.add_argument(
"--message-source",
default="both",
choices=["client", "server", "both"],
help="only include messages from the given source",
)
filter.add_argument(
filter_.add_argument(
"--include-message-type",
action="append",
default=[],
dest="include_message_types",
choices=["request", "response", "result", "error", "notification"],
help="only include the given message type(s)",
)
filter.add_argument(
filter_.add_argument(
"--exclude-message-type",
action="append",
dest="exclude_message_types",
default=[],
choices=["request", "response", "result", "error", "notification"],
help="omit the given message type(s)",
)
filter.add_argument(
filter_.add_argument(
"--include-method",
action="append",
dest="include_methods",
default=[],
metavar="METHOD",
help="only include the given messages for the given method(s)",
)
filter.add_argument(
filter_.add_argument(
"--exclude-method",
action="append",
dest="exclude_methods",
Expand Down Expand Up @@ -291,14 +291,14 @@ def cli(commands: argparse._SubParsersAction):
)

setup_filter_args(cmd)
format = cmd.add_argument_group(
format_ = cmd.add_argument_group(
title="formatting options",
description=(
"control how the recorded messages are formatted "
"(does not apply to SQLite output or raw message capture)"
),
)
format.add_argument(
format_.add_argument(
"-f",
"--format-message",
default=None,
Expand Down
2 changes: 1 addition & 1 deletion lib/lsp-devtools/lsp_devtools/record/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def filter(self, record: logging.LogRecord) -> bool:
message_type = get_message_type(message)
message_method = self._get_message_method(message_type, message)

if self.message_source != "both" and source != self.message_source:
if self.message_source not in {"both", source}:
return False

if self.include_message_types and not message_matches_type(
Expand Down
3 changes: 2 additions & 1 deletion lib/lsp-devtools/lsp_devtools/record/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def format(self, message: dict, accessor: Optional[str] = None) -> str:
if isinstance(index, int):
obj = obj[index]
continue
elif isinstance(index, slice):

if isinstance(index, slice):
obj = obj[index]

return sep.join([self.format(o, remainder) for o in obj])
Expand Down
4 changes: 0 additions & 4 deletions lib/lsp-devtools/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ show_missing = true
skip_covered = true
sort = "Cover"

[tool.isort]
force_single_line = true
profile = "black"

[tool.pyright]
venv = ".env"
include = ["lsp_devtools"]
Expand Down
77 changes: 77 additions & 0 deletions lib/lsp-devtools/ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
extend = "ruff_defaults.toml"
line-length = 88
indent-width = 4

[format]
# Be like black where possible
quote-style = "double"
indent-style = "space"
line-ending = "auto"
skip-magic-trailing-comma = false

[lint]
ignore = [
"BLE001", # catch Exception:
"INP001", # Complains about namespace packages
"PT018", # Assertion should be broken down into multiple parts
"T201", # print found
"TRY003", # Exception message defined outside of class

# The following were added when migrating to ruff, we might want to consider
# enabling some of these again at some point.
"A002", # argument shadowing
"ARG001", # unused function argument
"ARG002", # unused method argument
"C405", # rewrite as set literal
"C408", # dict(x=y)
"C416", # Unecessary dict comprehension
"C419", # Unecessary list comprehension
"E402", # module import not at top of file
"EM101", # raise ValueError("Literal string, not variable")
"EM102", # raise ValueError(f"-string, not variable")
"FBT001", # boolean arguments
"FBT002", # boolean arguments
"FLY002", # f-string alternative available
"G003", # logging statement uses f-string
"G004", # logging statement uses +
"G201", # logging.error(.., exc_info=True)
"N801", # naming conventions
"N802", # naming conventions
"N806", # naming conventions
"PERF401", # use list comprehension
"PERF402", # use list or list.copy
"PLR2004", # magic values
"PLW2901", # overwriting for-loop variable
"PT006", # Complains about how `pytest.mark.parametrize` parameters are passed
"PT011", # pytest.raises(ValueError)
"RET503", # Missing return
"RET504", # Unecessary assignment before return
"RET505", # Unecessary elif after return
"RUF001", # ambiguous characters
"RUF012", # Mutable ClassVar annotation...
"RUF015", # Prefer next(iter(...))
"SIM102", # Use single if
"SIM105", # Use contextlib.suppress(...)
"SIM108", # Use ternary operator
"SIM115", # Use key in dict
"SIM118", # Use key in dict
"SLF001", # private member access
"TCH001", # move import to type checking block
"TCH002", # move import to type checking block
"TCH003", # move import to type checking block
"TID252", # Absolute vs relative imports
"TRY300", # Move statement to else block
]

[lint.per-file-ignores]
"**/tests/**/*" = [
"S",
"SLF001", # private member accessed
]

[lint.isort]
force-single-line = true

[lint.pyupgrade]
# At least for now...
keep-runtime-typing = true
Loading

0 comments on commit 980113b

Please sign in to comment.