diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index f11d846..cf033d8 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -25,7 +25,6 @@ jobs: - "3.11" - "3.10" - "3.9" - - "3.8" - type - dev - pkg_meta diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 522e6fe..f12a84f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.4 + rev: 0.31.0 hooks: - id: check-github-workflows args: [ "--verbose" ] @@ -13,7 +13,7 @@ repos: rev: v2.3.0 hooks: - id: codespell - additional_dependencies: ["tomli>=2.0.1"] + additional_dependencies: ["tomli>=2.2.1"] - repo: https://github.com/tox-dev/tox-ini-fmt rev: "1.4.1" hooks: @@ -24,7 +24,7 @@ repos: hooks: - id: pyproject-fmt - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.8.0" + rev: "v0.9.2" hooks: - id: ruff-format - id: ruff diff --git a/docs/conf.py b/docs/conf.py index 815ad5a..6c5dba8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,11 +1,20 @@ # noqa: D100 from __future__ import annotations +from typing import TYPE_CHECKING + +from sphinx.domains.python import PythonDomain + from pyproject_api import __version__ +if TYPE_CHECKING: + from docutils.nodes import Element + from sphinx.application import Sphinx + from sphinx.builders import Builder + from sphinx.environment import BuildEnvironment project = name = "pyproject_api" company = "tox-dev" -copyright = f"{company}" # noqa: A001 +project_copyright = f"{company}" version, release = __version__, __version__.split("+")[0] extensions = [ @@ -38,3 +47,26 @@ nitpicky = True nitpick_ignore = [] + + +def setup(app: Sphinx) -> None: # noqa: D103 + class PatchedPythonDomain(PythonDomain): + def resolve_xref( # noqa: PLR0913,PLR0917 + self, + env: BuildEnvironment, + fromdocname: str, + builder: Builder, + type: str, # noqa: A002 + target: str, + node: resolve_xref, + contnode: Element, + ) -> Element: + # fixup some wrongly resolved mappings + mapping = { + "pathlib._local.Path": "pathlib.Path", + } + if target in mapping: + target = node["reftarget"] = mapping[target] + return super().resolve_xref(env, fromdocname, builder, type, target, node, contnode) + + app.add_domain(PatchedPythonDomain, override=True) diff --git a/pyproject.toml b/pyproject.toml index c5233f6..ebda985 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ build-backend = "hatchling.build" requires = [ "hatch-vcs>=0.4", - "hatchling>=1.25", + "hatchling>=1.27", ] [project] @@ -23,7 +23,7 @@ maintainers = [ authors = [ { name = "Bernát Gábor", email = "gaborjbernat@gmail.com" }, ] -requires-python = ">=3.8" +requires-python = ">=3.9" classifiers = [ "Development Status :: 5 - Production/Stable", "Framework :: tox", @@ -33,7 +33,6 @@ classifiers = [ "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -47,19 +46,19 @@ dynamic = [ "version", ] dependencies = [ - "packaging>=24.1", - "tomli>=2.0.1; python_version<'3.11'", + "packaging>=24.2", + "tomli>=2.2.1; python_version<'3.11'", ] optional-dependencies.docs = [ "furo>=2024.8.6", - "sphinx-autodoc-typehints>=2.4.1", + "sphinx-autodoc-typehints>=3", ] optional-dependencies.testing = [ "covdefaults>=2.3", - "pytest>=8.3.3", - "pytest-cov>=5", + "pytest>=8.3.4", + "pytest-cov>=6", "pytest-mock>=3.14", - "setuptools>=75.1", + "setuptools>=75.8", ] urls.Changelog = "https://github.com/tox-dev/pyproject-api/releases" urls.Homepage = "https://pyproject-api.readthedocs.io" @@ -71,7 +70,6 @@ build.hooks.vcs.version-file = "src/pyproject_api/_version.py" version.source = "vcs" [tool.ruff] -target-version = "py38" line-length = 120 format.preview = true format.docstring-code-line-length = 100 diff --git a/src/pyproject_api/_backend.pyi b/src/pyproject_api/_backend.pyi index ba33557..8c5f75f 100644 --- a/src/pyproject_api/_backend.pyi +++ b/src/pyproject_api/_backend.pyi @@ -1,4 +1,5 @@ -from typing import Any, Sequence +from collections.abc import Sequence +from typing import Any class MissingCommand(TypeError): ... # noqa: N818 diff --git a/src/pyproject_api/_frontend.py b/src/pyproject_api/_frontend.py index 8c86bc0..0489c1c 100644 --- a/src/pyproject_api/_frontend.py +++ b/src/pyproject_api/_frontend.py @@ -9,20 +9,23 @@ from pathlib import Path from tempfile import NamedTemporaryFile, TemporaryDirectory from time import sleep -from typing import Any, Dict, Iterator, List, Literal, NamedTuple, NoReturn, Optional, TypedDict, cast +from typing import TYPE_CHECKING, Any, Literal, NamedTuple, NoReturn, Optional, TypedDict, cast from zipfile import ZipFile from packaging.requirements import Requirement from pyproject_api._util import ensure_empty_dir +if TYPE_CHECKING: + from collections.abc import Iterator + if sys.version_info >= (3, 11): # pragma: no cover (py311+) import tomllib else: # pragma: no cover (py311+) import tomli as tomllib _HERE = Path(__file__).parent -ConfigSettings = Optional[Dict[str, Any]] +ConfigSettings = Optional[dict[str, Any]] class OptionalHooks(TypedDict, total=True): @@ -276,7 +279,7 @@ def get_requires_for_build_sdist(self, config_settings: ConfigSettings | None = result, out, err = [], "", "" if not isinstance(result, list) or not all(isinstance(i, str) for i in result): self._unexpected_response("get_requires_for_build_sdist", result, "list of string", out, err) - return RequiresBuildSdistResult(tuple(Requirement(r) for r in cast(List[str], result)), out, err) + return RequiresBuildSdistResult(tuple(Requirement(r) for r in cast("list[str]", result)), out, err) def get_requires_for_build_wheel(self, config_settings: ConfigSettings | None = None) -> RequiresBuildWheelResult: """ @@ -291,7 +294,7 @@ def get_requires_for_build_wheel(self, config_settings: ConfigSettings | None = result, out, err = [], "", "" if not isinstance(result, list) or not all(isinstance(i, str) for i in result): self._unexpected_response("get_requires_for_build_wheel", result, "list of string", out, err) - return RequiresBuildWheelResult(tuple(Requirement(r) for r in cast(List[str], result)), out, err) + return RequiresBuildWheelResult(tuple(Requirement(r) for r in cast("list[str]", result)), out, err) def get_requires_for_build_editable( self, @@ -309,7 +312,7 @@ def get_requires_for_build_editable( result, out, err = [], "", "" if not isinstance(result, list) or not all(isinstance(i, str) for i in result): self._unexpected_response("get_requires_for_build_editable", result, "list of string", out, err) - return RequiresBuildEditableResult(tuple(Requirement(r) for r in cast(List[str], result)), out, err) + return RequiresBuildEditableResult(tuple(Requirement(r) for r in cast("list[str]", result)), out, err) def prepare_metadata_for_build_wheel( self, diff --git a/src/pyproject_api/_via_fresh_subprocess.py b/src/pyproject_api/_via_fresh_subprocess.py index 86540f7..d942ac0 100644 --- a/src/pyproject_api/_via_fresh_subprocess.py +++ b/src/pyproject_api/_via_fresh_subprocess.py @@ -5,11 +5,12 @@ from contextlib import contextmanager from subprocess import PIPE, Popen # noqa: S404 from threading import Thread -from typing import IO, TYPE_CHECKING, Any, Iterator, Tuple, cast +from typing import IO, TYPE_CHECKING, Any, cast from ._frontend import CmdStatus, Frontend if TYPE_CHECKING: + from collections.abc import Iterator from pathlib import Path from packaging.requirements import Requirement @@ -30,7 +31,7 @@ def done(self) -> bool: return self.process.returncode is not None def out_err(self) -> tuple[str, str]: - return cast(Tuple[str, str], self._out_err) + return cast("tuple[str, str]", self._out_err) class SubprocessFrontend(Frontend): @@ -71,7 +72,7 @@ def _send_msg(self, cmd: str, result_file: Path, msg: str) -> Iterator[Subproces cwd=self._root, env=env, ) - cast(IO[str], process.stdin).write(f"{os.linesep}{msg}{os.linesep}") + cast("IO[str]", process.stdin).write(f"{os.linesep}{msg}{os.linesep}") yield SubprocessCmdStatus(process) def send_cmd(self, cmd: str, **kwargs: Any) -> tuple[Any, str, str]: diff --git a/tests/test_frontend.py b/tests/test_frontend.py index 780b717..41fec4b 100644 --- a/tests/test_frontend.py +++ b/tests/test_frontend.py @@ -177,7 +177,7 @@ def test_no_wheel_prepare_metadata_for_build_wheel(local_builder: Callable[[str] tmp_path = local_builder(txt) frontend = SubprocessFrontend(*SubprocessFrontend.create_args_from_folder(tmp_path)[:-1]) - with pytest.raises(RuntimeError, match="missing wheel file return by backed *"): + with pytest.raises(RuntimeError, match=r"missing wheel file return by backed *"): frontend.metadata_from_built(tmp_path, "wheel") @@ -213,7 +213,7 @@ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): tmp_path = local_builder(txt) frontend = SubprocessFrontend(*SubprocessFrontend.create_args_from_folder(tmp_path)[:-1]) - with pytest.raises(RuntimeError, match="no .dist-info found inside generated wheel*"): + with pytest.raises(RuntimeError, match=r"no .dist-info found inside generated wheel*"): frontend.metadata_from_built(tmp_path, "wheel") diff --git a/tests/test_frontend_setuptools.py b/tests/test_frontend_setuptools.py index a08dc06..4f22816 100644 --- a/tests/test_frontend_setuptools.py +++ b/tests/test_frontend_setuptools.py @@ -3,7 +3,7 @@ import sys from contextlib import contextmanager from stat import S_IWGRP, S_IWOTH, S_IWUSR -from typing import TYPE_CHECKING, Iterator, NamedTuple +from typing import TYPE_CHECKING, NamedTuple import pytest @@ -11,6 +11,7 @@ from pyproject_api._via_fresh_subprocess import SubprocessFrontend if TYPE_CHECKING: + from collections.abc import Iterator from pathlib import Path from _pytest.tmpdir import TempPathFactory diff --git a/tox.ini b/tox.ini index 771dbc2..704e896 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] requires = - tox>=4.2 - tox-uv>=1.11 + tox>=4.23.2 + tox-uv>=1.17 env_list = fix 3.13 @@ -9,7 +9,6 @@ env_list = 3.11 3.10 3.9 - 3.8 docs type pkg_meta @@ -40,7 +39,7 @@ commands = description = run static analysis and style check using flake8 package = skip deps = - pre-commit-uv>=4.1.1 + pre-commit-uv>=4.1.4 pass_env = HOMEPATH PROGRAMDATA @@ -53,13 +52,13 @@ description = build documentation extras = docs commands = - sphinx-build -d "{env_tmp_dir}{/}doc_tree" docs "{work_dir}{/}docs_out" --color -b html {posargs} -W + sphinx-build -d "{env_tmp_dir}{/}doc_tree" docs "{work_dir}{/}docs_out" --color -b html {posargs: -W} python -c 'print(r"documentation available under file://{work_dir}{/}docs_out{/}index.html")' [testenv:type] description = run type check on code base deps = - mypy==1.11.2 + mypy==1.14.1 set_env = {tty:MYPY_FORCE_COLOR = 1} commands = @@ -70,9 +69,9 @@ commands = description = check that the long description is valid skip_install = true deps = - check-wheel-contents>=0.6 - twine>=5.1.1 - uv>=0.4.10 + check-wheel-contents>=0.6.1 + twine>=6.0.1 + uv>=0.5.18 commands = uv build --sdist --wheel --out-dir {env_tmp_dir} . twine check {env_tmp_dir}{/}*