Skip to content

Commit a7914ce

Browse files
authored
upgrade python and linters (PR 1/3) (#32)
* upgrade python and linters * update test matrix * remove python 3.14 since pyo3 used by maturin doesn't support that
1 parent f287237 commit a7914ce

22 files changed

Lines changed: 209 additions & 193 deletions

.github/workflows/test.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ on:
2020
default: '3.13'
2121
options:
2222
- 'all'
23-
- '3.9'
23+
- '3.11'
2424
- '3.13t'
2525
- '3.13'
26-
- 'pypy3.9'
27-
- 'pypy3.10'
26+
- 'pypy3.11'
2827
test_specification:
2928
type: string
3029
description: Specification for the tests to run
@@ -57,11 +56,10 @@ jobs:
5756
- macos-14
5857
- windows-latest
5958
PYTHON_VERSION: |
60-
- '3.9'
59+
- '3.11'
6160
- '3.13t'
6261
- '3.13'
63-
- 'pypy3.9'
64-
- 'pypy3.10'
62+
- 'pypy3.11'
6563
steps:
6664
- uses: actions/setup-node@v4
6765
with:

.pre-commit-config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v5.0.0
3+
rev: v6.0.0
44
hooks:
55
- id: check-yaml
66
- id: check-toml
77
- id: end-of-file-fixer
88
- id: trailing-whitespace
99
- id: mixed-line-ending
1010
- repo: https://github.com/astral-sh/ruff-pre-commit
11-
rev: v0.11.13
11+
rev: v0.15.21
1212
hooks:
1313
- id: ruff-format
1414
- id: ruff
1515
args: [ --fix ]
1616
- repo: https://github.com/pre-commit/mirrors-mypy
17-
rev: v1.16.0
17+
rev: v2.2.0
1818
hooks:
1919
# note: mypy runs in an isolated environment and so has no access to third party packages
2020
- id: mypy
2121
entry: mypy src/maturin_import_hook/ tests/test_import_hook tests/runner.py
2222
pass_filenames: false
2323
additional_dependencies: ["pytest"]
2424
- repo: https://github.com/codespell-project/codespell
25-
rev: v2.4.1
25+
rev: v2.4.2
2626
hooks:
2727
- id: codespell
2828
- repo: https://github.com/igorshubovych/markdownlint-cli
29-
rev: v0.45.0
29+
rev: v0.49.0
3030
hooks:
3131
- id: markdownlint-fix

pyproject.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ authors = [
66
]
77
readme = "README.md"
88
version = "0.3.0"
9-
requires-python = ">=3.9"
9+
requires-python = ">=3.11"
1010
dependencies = [
1111
"filelock",
12-
"tomli>=1.1.0 ; python_version<'3.11'"
1312
]
1413
classifiers = [
1514
"Development Status :: 5 - Production/Stable",
@@ -28,12 +27,17 @@ Repository = "https://github.com/PyO3/maturin-import-hook.git"
2827
Issues = "https://github.com/PyO3/maturin-import-hook/issues"
2928
Changelog = "https://github.com/PyO3/maturin-import-hook/blob/main/Changelog.md"
3029

30+
[dependency-groups]
31+
dev = [
32+
"pytest>=8.4.2",
33+
]
34+
3135
[tool.setuptools.packages.find]
3236
where = ["src"]
3337

3438
[tool.ruff]
3539
line-length = 120
36-
target-version = "py39"
40+
target-version = "py311"
3741

3842
[tool.ruff.format]
3943
preview = true
@@ -69,7 +73,7 @@ ignore = [
6973
]
7074

7175
[tool.mypy]
72-
python_version = "3.9"
76+
python_version = "3.11"
7377
strict = true
7478
allow_redefinition = true
7579
exclude = [

src/maturin_import_hook/__init__.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
22
from pathlib import Path
3-
from typing import Optional
43

54
from maturin_import_hook import project_importer, rust_file_importer
65
from maturin_import_hook._logging import logger, reset_logger
@@ -14,12 +13,12 @@ def install(
1413
enable_project_importer: bool = True,
1514
enable_rs_file_importer: bool = True,
1615
enable_reloading: bool = True,
17-
settings: Optional[MaturinSettings] = None,
18-
build_dir: Optional[Path] = None,
16+
settings: MaturinSettings | None = None,
17+
build_dir: Path | None = None,
1918
force_rebuild: bool = False,
20-
lock_timeout_seconds: Optional[float] = 120,
19+
lock_timeout_seconds: float | None = 120,
2120
show_warnings: bool = True,
22-
file_searcher: Optional[project_importer.ProjectFileSearcher] = None,
21+
file_searcher: project_importer.ProjectFileSearcher | None = None,
2322
enable_automatic_installation: bool = False,
2423
) -> None:
2524
"""Install import hooks for automatically rebuilding and importing maturin projects or .rs files.

src/maturin_import_hook/__main__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import site
77
import subprocess
88
from pathlib import Path
9-
from typing import Optional
109

1110
from maturin_import_hook import project_importer, rust_file_importer
1211
from maturin_import_hook._building import get_default_build_dir
@@ -106,7 +105,7 @@ def _action_site_install(
106105
*,
107106
user: bool,
108107
force: bool,
109-
args: Optional[str],
108+
args: str | None,
110109
enable_project_importer: bool,
111110
enable_rs_file_importer: bool,
112111
) -> None:

src/maturin_import_hook/_building.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import hashlib
24
import json
35
import logging
@@ -8,18 +10,21 @@
810
import subprocess
911
import sys
1012
import zipfile
11-
from collections.abc import Generator, Iterable
1213
from contextlib import contextmanager
1314
from dataclasses import dataclass
1415
from operator import itemgetter
1516
from pathlib import Path
16-
from typing import Any, Optional
17+
from typing import TYPE_CHECKING, Any
1718

1819
import filelock
1920

2021
from maturin_import_hook._logging import logger
2122
from maturin_import_hook.error import ImportHookError, MaturinError
22-
from maturin_import_hook.settings import MaturinSettings
23+
24+
if TYPE_CHECKING:
25+
from collections.abc import Generator, Iterable
26+
27+
from maturin_import_hook.settings import MaturinSettings
2328

2429

2530
@dataclass
@@ -43,7 +48,7 @@ def to_json(self) -> dict[str, Any]:
4348
}
4449

4550
@staticmethod
46-
def from_json(json_data: dict[Any, Any]) -> Optional["BuildStatus"]:
51+
def from_json(json_data: dict[Any, Any]) -> BuildStatus | None:
4752
try:
4853
return BuildStatus(
4954
build_mtime=json_data["build_mtime"],
@@ -70,7 +75,7 @@ def store_build_status(self, build_status: BuildStatus) -> None:
7075
with self._build_status_path(build_status.source_path).open("w") as f:
7176
json.dump(build_status.to_json(), f, indent=" ")
7277

73-
def get_build_status(self, source_path: Path) -> Optional[BuildStatus]:
78+
def get_build_status(self, source_path: Path) -> BuildStatus | None:
7479
try:
7580
with self._build_status_path(source_path).open("r") as f:
7681
return BuildStatus.from_json(json.load(f))
@@ -83,7 +88,7 @@ def tmp_project_dir(self, project_path: Path, module_name: str) -> Path:
8388

8489

8590
class BuildCache:
86-
def __init__(self, build_dir: Optional[Path], lock_timeout_seconds: Optional[float]) -> None:
91+
def __init__(self, build_dir: Path | None, lock_timeout_seconds: float | None) -> None:
8792
self._build_dir = build_dir if build_dir is not None else get_default_build_dir()
8893
self._lock = filelock.FileLock(
8994
self._build_dir / "lock", timeout=-1 if lock_timeout_seconds is None else lock_timeout_seconds
@@ -96,7 +101,7 @@ def lock(self) -> Generator[LockedBuildCache, None, None]:
96101

97102

98103
@contextmanager
99-
def _acquire_lock(lock: filelock.FileLock) -> Generator[None, None, None]:
104+
def _acquire_lock(lock: filelock.BaseFileLock) -> Generator[None, None, None]:
100105
try:
101106
try:
102107
with lock.acquire(blocking=False):
@@ -245,7 +250,7 @@ def build_unpacked_wheel(maturin_path: Path, manifest_path: Path, output_dir: Pa
245250
return output
246251

247252

248-
def _find_single_file(dir_path: Path, extension: Optional[str]) -> Optional[Path]:
253+
def _find_single_file(dir_path: Path, extension: str | None) -> Path | None:
249254
if dir_path.exists():
250255
candidate_files = [p for p in dir_path.iterdir() if extension is None or p.suffix == extension]
251256
else:
@@ -261,8 +266,8 @@ def maturin_output_has_warnings(output: str) -> bool:
261266
class Freshness:
262267
is_fresh: bool
263268
reason: str
264-
oldest_installed_path: Optional[Path]
265-
newest_source_path: Optional[Path]
269+
oldest_installed_path: Path | None
270+
newest_source_path: Path | None
266271

267272

268273
def get_installation_freshness(
@@ -326,7 +331,7 @@ def get_installation_freshness(
326331
return Freshness(True, "", oldest_installed_path, newest_source_path)
327332

328333

329-
def get_installation_mtime(installed_paths: Iterable[Path]) -> Optional[float]:
334+
def get_installation_mtime(installed_paths: Iterable[Path]) -> float | None:
330335
try:
331336
installation_mtime = min(path.stat().st_mtime for path in installed_paths)
332337
except ValueError:

src/maturin_import_hook/_common.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import shutil
33
import tempfile
44
from pathlib import Path
5-
from typing import Optional
65

76
from maturin_import_hook._logging import logger
87

@@ -12,7 +11,7 @@ class LazySessionTemporaryDirectory:
1211

1312
def __init__(self, *, prefix: str) -> None:
1413
self._prefix = prefix
15-
self._tmp_path: Optional[Path] = None
14+
self._tmp_path: Path | None = None
1615

1716
def __del__(self) -> None:
1817
self._cleanup()

src/maturin_import_hook/_resolve_project.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import itertools
2+
import tomllib
23
from dataclasses import dataclass
34
from pathlib import Path
45
from typing import Any, Optional, TypeVar
56

67
from maturin_import_hook._logging import logger
78

8-
try:
9-
import tomllib
10-
except ModuleNotFoundError:
11-
import tomli as tomllib
12-
13-
149
_T = TypeVar("_T")
1510

1611

@@ -33,7 +28,7 @@ def get_value_or_default(self, keys: list[str], required_type: type[_T], default
3328
value = self.get_value(keys, required_type)
3429
return default if value is None else value
3530

36-
def get_value(self, keys: list[str], required_type: type[_T]) -> Optional[_T]:
31+
def get_value(self, keys: list[str], required_type: type[_T]) -> _T | None:
3732
assert keys
3833
current_data: Any = self.data
3934
num_keys = len(keys)
@@ -58,7 +53,7 @@ def get_value(self, keys: list[str], required_type: type[_T]) -> Optional[_T]:
5853
return current_data
5954

6055

61-
def find_cargo_manifest(project_dir: Path) -> Optional[Path]:
56+
def find_cargo_manifest(project_dir: Path) -> Path | None:
6257
pyproject_path = project_dir / "pyproject.toml"
6358
if pyproject_path.is_file():
6459
pyproject_data = pyproject_path.read_text()
@@ -88,7 +83,7 @@ def is_maybe_maturin_project(directory: Path) -> bool:
8883

8984
class ProjectResolver:
9085
def __init__(self) -> None:
91-
self._resolved_project_cache: dict[Path, Optional[MaturinProject]] = {}
86+
self._resolved_project_cache: dict[Path, MaturinProject | None] = {}
9287

9388
def clear_cache(self) -> None:
9489
self._resolved_project_cache.clear()
@@ -115,13 +110,13 @@ class MaturinProject:
115110
# the root of the python part of the project (or the project root if there is none)
116111
python_dir: Path
117112
# the path to the top level python package if the project is mixed
118-
python_module: Optional[Path]
113+
python_module: Path | None
119114
# the location that the compiled extension module is written to when installed in editable/unpacked mode
120-
extension_module_dir: Optional[Path]
115+
extension_module_dir: Path | None
121116
# path dependencies listed in the Cargo.toml of the main project
122117
immediate_path_dependencies: list[Path]
123118
# all path dependencies including transitive dependencies
124-
_all_path_dependencies: Optional[list[Path]] = None
119+
_all_path_dependencies: list[Path] | None = None
125120

126121
@property
127122
def package_name(self) -> str:
@@ -204,8 +199,8 @@ def _resolve_project(project_dir: Path) -> MaturinProject:
204199

205200
python_dir = _resolve_py_root(project_dir, pyproject)
206201

207-
extension_module_dir: Optional[Path]
208-
python_module: Optional[Path]
202+
extension_module_dir: Path | None
203+
python_module: Path | None
209204
python_module, extension_module_dir, _extension_module_name = _resolve_rust_module(python_dir, module_full_name)
210205
immediate_path_dependencies = _get_immediate_path_dependencies(manifest_path.parent, cargo)
211206

@@ -248,7 +243,7 @@ def _resolve_rust_module(python_dir: Path, module_name: str) -> tuple[Path, Path
248243
return python_module, extension_module_dir, extension_module_name
249244

250245

251-
def _resolve_module_name(pyproject: _TomlFile, cargo: _TomlFile) -> Optional[str]:
246+
def _resolve_module_name(pyproject: _TomlFile, cargo: _TomlFile) -> str | None:
252247
"""This follows the same logic as project_layout.rs (ProjectResolver::resolve).
253248
254249
Precedence:

src/maturin_import_hook/_site.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import shlex
33
import site
44
from pathlib import Path
5-
from typing import Optional
65

76
from maturin_import_hook._logging import logger
87
from maturin_import_hook.settings import MaturinSettings
@@ -85,7 +84,7 @@ def insert_automatic_installation(
8584
module_path: Path,
8685
uninstall_command: str,
8786
force: bool,
88-
args: Optional[str],
87+
args: str | None,
8988
enable_project_importer: bool,
9089
enable_rs_file_importer: bool,
9190
) -> None:

0 commit comments

Comments
 (0)