Skip to content

Commit 0bb0524

Browse files
committed
refactor: use linters in the env, fix mypy warns, improve makefiles
1 parent e08131f commit 0bb0524

15 files changed

Lines changed: 1014 additions & 714 deletions

File tree

.github/workflows/test.yml

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,9 @@ jobs:
4141
distribution: 'temurin'
4242
java-version: '26'
4343

44-
- name: Install dependencies
45-
run: |
46-
uv sync --group tests --frozen
47-
48-
- name: Verify installed packages
49-
run: |
50-
uv pip list
51-
52-
- name: Import language_tool_python
53-
run: |
54-
printf "import language_tool_python\n" | uv run python
55-
5644
- name: Test with pytest
5745
run: |
58-
uv run pytest
46+
make test
5947
6048
lint:
6149
timeout-minutes: 10
@@ -71,8 +59,7 @@ jobs:
7159
# Keep in sync ruff version with .pre-commit-config.yaml
7260
- name: Run Ruff Linter
7361
run: |
74-
uvx ruff@0.15.12 check .
75-
uvx ruff@0.15.12 format --check .
62+
make ruff-check
7663
7764
type_check:
7865
timeout-minutes: 10
@@ -84,12 +71,8 @@ jobs:
8471

8572
- name: Install uv
8673
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # 8.1.0
87-
88-
- name: Install dependencies
89-
run: |
90-
uv sync --group types --frozen
9174

9275
# Keep in sync mypy version with .pre-commit-config.yaml
9376
- name: Run Mypy Type Checker
9477
run: |
95-
uvx mypy@2.0.0
78+
make mypy-check

CONTRIBUTING.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ If you want to contribute, you first need to fork the repo (and preferably creat
2020

2121
To start developing, you can install all the necessary packages in your python environment with this command (optional dependencies will be installed):
2222
```shell
23-
uv sync --group tests --group docs --group types
23+
make install
2424
```
2525

2626
When pushing commits, please use the project naming conventions, which are available in [this guide](https://www.conventionalcommits.org/en/v1.0.0/).
@@ -30,17 +30,14 @@ The documentation style used in the project is **ReStructuredText**. Please, if
3030

3131
Before creating your pull request, when you have made all your commits, you need to run this:
3232
```shell
33-
# Run linters (maybe you will have to fix some issues)
34-
uvx ruff@0.15.12 check language_tool_python tests
33+
# Format your code
34+
make format
3535

36-
# Format code
37-
uvx ruff@0.15.12 format language_tool_python tests
36+
# Run linters, check code formatting and types (maybe you will have to fix some issues)
37+
make check
3838

39-
# Check types
40-
uvx mypy@2.0.0
41-
42-
# Tests
43-
pytest
39+
# Run tests (if you have added or modified some, make sure they are passing)
40+
make test
4441
```
4542

4643
Please do not manually bump the version number in [pyproject.toml](./pyproject.toml), this will be handled by the maintainers during release.

Makefile

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,45 @@
1-
.PHONY: default check test doc publish
1+
.PHONY: default install format ruff-check mypy-check check test doc publish
2+
3+
UV := $(shell command -v uv 2>/dev/null || true)
4+
ifeq ($(UV),)
5+
$(warning uv not found. Install uv (curl -LsSf https://astral.sh/uv/install.sh | sh) to use Makefile targets)
6+
endif
27

38
default:
4-
@echo "Usage: make [check|test|doc|publish]"
9+
@echo "Usage: make [install|format|ruff-check|mypy-check|check|test|doc|publish]"
510
@exit 1
611

12+
install:
13+
uv sync --all-groups --frozen
14+
15+
format:
16+
uv run --all-groups --frozen ruff format language_tool_python tests
17+
18+
ruff-check:
19+
uv run --all-groups --frozen ruff check language_tool_python tests
20+
uv run --all-groups --frozen ruff format --check language_tool_python tests
21+
22+
mypy-check:
23+
@if uv run --frozen python -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)'; then \
24+
uv run --all-groups --frozen mypy; \
25+
else \
26+
echo "Skipping mypy: Python 3.10 or newer is required."; \
27+
fi
28+
729
check:
8-
uvx ruff@0.15.12 check language_tool_python tests
9-
uvx ruff@0.15.12 format --check language_tool_python tests
10-
uvx mypy@2.0.0
30+
make ruff-check
31+
make mypy-check
1132

1233
test:
13-
pytest
34+
uv run --group tests --frozen pytest
1435
uvx --with defusedxml genbadge coverage --input-file coverage.xml --silent
36+
1537
doc:
16-
source ./.venv/bin/activate && uv run sphinx-apidoc -o docs/source/references language_tool_python
38+
uv run --all-groups --frozen sphinx-apidoc -o docs/source/references language_tool_python
1739
source ./.venv/bin/activate && cd ./docs && make html
1840

1941
publish:
20-
rm -rf dist/ language_tool_python.egg-info/
42+
rm -rf dist/
2143
uv build
2244
uvx twine check dist/*
2345
uv publish

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,15 +388,16 @@ Main exceptions in `language_tool_python.exceptions`:
388388

389389
```bash
390390
# Install dev dependencies
391-
uv sync --group tests --group docs --group types
391+
make install
392+
393+
# Format code
394+
make format
392395

393396
# Lint / format / types
394-
uvx ruff@0.15.12 check .
395-
uvx ruff@0.15.12 format .
396-
uvx mypy@2.0.0
397+
make check
397398

398399
# Tests
399-
pytest
400+
make test
400401
```
401402

402403
## License

language_tool_python/_deprecated.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
"""
99

1010
try:
11-
from warnings import deprecated # type: ignore [attr-defined]
11+
from warnings import deprecated # type: ignore [attr-defined, unused-ignore]
1212
except ImportError:
1313
import functools
1414
from typing import Any, Callable, Optional, Type, TypeVar, cast
1515
from warnings import warn
1616

1717
F = TypeVar("F", bound=Callable[..., Any])
1818

19-
def deprecated(
19+
def deprecated( # type: ignore [no-redef, unused-ignore]
2020
message: str,
2121
/,
2222
*,

language_tool_python/download_lt.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def confirm_java_compatibility(
242242
@deprecated(
243243
"This function is no longer used internally and will be removed in 4.0.",
244244
stacklevel=2,
245-
) # type: ignore
245+
) # type: ignore[untyped-decorator, unused-ignore]
246246
def get_common_prefix(z: zipfile.ZipFile) -> Optional[str]:
247247
"""
248248
Determine the common prefix of all file names in a zip archive.
@@ -265,7 +265,7 @@ def get_common_prefix(z: zipfile.ZipFile) -> Optional[str]:
265265
@deprecated(
266266
"This function is no longer used internally and will be removed in 4.0.",
267267
stacklevel=2,
268-
) # type: ignore
268+
) # type: ignore[untyped-decorator, unused-ignore]
269269
def http_get(
270270
url: str,
271271
out_file: IO[bytes],
@@ -287,14 +287,14 @@ def http_get(
287287
# Fallback to default behavior if the extracted version is not supported
288288
local_lt = LocalLanguageTool.from_version_name(LTP_DOWNLOAD_VERSION)
289289

290-
with local_lt._get_remote_zip(out_file, proxies=proxies): # type: ignore
290+
with local_lt._get_remote_zip(out_file, proxies=proxies):
291291
pass
292292

293293

294294
@deprecated(
295295
"This function is no longer used internally and will be removed in 4.0.",
296296
stacklevel=2,
297-
) # type: ignore
297+
) # type: ignore[untyped-decorator, unused-ignore]
298298
def unzip_file(temp_file_name: str, directory_to_extract_to: Path) -> None:
299299
"""
300300
Unzips a zip file to a specified directory.
@@ -323,7 +323,7 @@ def unzip_file(temp_file_name: str, directory_to_extract_to: Path) -> None:
323323
@deprecated(
324324
"This function is no longer used internally and will be removed in 4.0.",
325325
stacklevel=2,
326-
) # type: ignore
326+
) # type: ignore[untyped-decorator, unused-ignore]
327327
def download_zip(url: str, directory: Path) -> None:
328328
"""
329329
Downloads a ZIP file from the given URL and extracts it to the specified directory.
@@ -339,18 +339,18 @@ def download_zip(url: str, directory: Path) -> None:
339339
logger.info("Downloading from %s to %s", url, directory)
340340
# Download file using a context manager.
341341
with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as downloaded_file:
342-
http_get(url, downloaded_file) # type: ignore
342+
http_get(url, downloaded_file)
343343
temp_name = downloaded_file.name
344344
# Extract zip file to path.
345-
unzip_file(temp_name, directory) # type: ignore
345+
unzip_file(temp_name, directory)
346346
# Remove the temporary file.
347347
Path(temp_name).unlink(missing_ok=True)
348348

349349

350350
@deprecated(
351351
"This function is no longer used internally and will be removed in 4.0.\nUse instead language_tool_python.download_lt.LocalLanguageTool.download.",
352352
stacklevel=2,
353-
) # type: ignore
353+
) # type: ignore[untyped-decorator, unused-ignore]
354354
def download_lt(language_tool_version: str = LTP_DOWNLOAD_VERSION) -> None:
355355
"""
356356
Downloads and extracts the specified version of LanguageTool.
@@ -731,7 +731,11 @@ def __lt__(self, other: object) -> bool:
731731
# At this point, both objects are the same type, so version_into will be the same type
732732
self_version = self.version_into
733733
other_version = other.version_into
734-
return self_version < other_version # type: ignore
734+
if isinstance(self_version, Version) and isinstance(other_version, Version):
735+
return self_version < other_version
736+
if isinstance(self_version, datetime) and isinstance(other_version, datetime):
737+
return self_version < other_version
738+
return NotImplemented
735739

736740

737741
class ReleaseLocalLanguageTool(LocalLanguageTool):

language_tool_python/utils.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def get_language_tool_download_path() -> Path:
205205
@deprecated(
206206
"This function is no longer used internally and will be removed in 4.0.\nReplace its usage by an inline alternative.",
207207
stacklevel=2,
208-
) # type: ignore
208+
) # type: ignore[untyped-decorator, unused-ignore]
209209
def find_existing_language_tool_downloads(download_folder: Path) -> List[Path]:
210210
"""
211211
Find existing LanguageTool downloads in the specified folder.
@@ -226,7 +226,7 @@ def find_existing_language_tool_downloads(download_folder: Path) -> List[Path]:
226226
@deprecated(
227227
"This function is no longer used internally and will be removed in 4.0.",
228228
stacklevel=2,
229-
) # type: ignore
229+
) # type: ignore[untyped-decorator, unused-ignore]
230230
def _extract_version(path: Path) -> version.Version:
231231
"""
232232
Extract the version number from a LanguageTool directory path.
@@ -256,7 +256,7 @@ def _extract_version(path: Path) -> version.Version:
256256
@deprecated(
257257
"This function is no longer used internally and will be removed in 4.0.\nUse instead language_tool_python.download_lt.LocalLanguageTool.get_latest_installed_version.",
258258
stacklevel=2,
259-
) # type: ignore
259+
) # type: ignore[untyped-decorator, unused-ignore]
260260
def get_language_tool_directory() -> Path:
261261
"""
262262
Get the directory path of the LanguageTool installation.
@@ -277,7 +277,7 @@ def get_language_tool_directory() -> Path:
277277
if not download_folder.is_dir():
278278
err = f"LanguageTool directory path is not a valid directory {download_folder}."
279279
raise NotADirectoryError(err)
280-
language_tool_path_list = find_existing_language_tool_downloads(download_folder) # type: ignore
280+
language_tool_path_list = find_existing_language_tool_downloads(download_folder)
281281

282282
if not len(language_tool_path_list):
283283
err = f"LanguageTool not found in {download_folder}."
@@ -286,7 +286,7 @@ def get_language_tool_directory() -> Path:
286286
# Return the latest version found in the directory.
287287
latest: Path = max(
288288
language_tool_path_list,
289-
key=_extract_version, # type: ignore
289+
key=_extract_version,
290290
)
291291
logger.debug("Using LanguageTool directory: %s", latest)
292292
return latest
@@ -295,7 +295,7 @@ def get_language_tool_directory() -> Path:
295295
@deprecated(
296296
"This function is no longer used internally and will be removed in 4.0.\nUse instead language_tool_python.download_lt.LocalLanguageTool.get_server_cmd.",
297297
stacklevel=2,
298-
) # type: ignore
298+
) # type: ignore[untyped-decorator, unused-ignore]
299299
def get_server_cmd(
300300
port: Optional[int] = None,
301301
config: Optional[LanguageToolConfig] = None,
@@ -313,7 +313,7 @@ def get_server_cmd(
313313
.. deprecated:: 3.3.0
314314
This function is no longer used internally and will be removed in 4.0.
315315
"""
316-
java_path, jar_path = get_jar_info() # type: ignore
316+
java_path, jar_path = get_jar_info()
317317
cmd = [
318318
str(java_path),
319319
"-cp",
@@ -334,7 +334,7 @@ def get_server_cmd(
334334
@deprecated(
335335
"This function is no longer used internally and will be removed in 4.0.",
336336
stacklevel=2,
337-
) # type: ignore
337+
) # type: ignore[untyped-decorator, unused-ignore]
338338
def get_jar_info() -> Tuple[Path, Path]:
339339
"""
340340
Retrieve the path to the Java executable and the LanguageTool JAR file.
@@ -361,7 +361,7 @@ def get_jar_info() -> Tuple[Path, Path]:
361361
# otherwise look in the download directory
362362
jar_dir_name = os.environ.get(
363363
LTP_JAR_DIR_PATH_ENV_VAR,
364-
get_language_tool_directory(), # type: ignore
364+
get_language_tool_directory(),
365365
)
366366
jar_path = None
367367
for jar_name in JAR_NAMES:

0 commit comments

Comments
 (0)