diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 58c9ab7..5929e1a 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -14,32 +14,36 @@ concurrency: jobs: test: - name: test with ${{ matrix.py }} + name: test ${{ matrix.py }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: py: + - "3.13" - "3.12" - "3.11" - "3.10" - "3.9" steps: - - uses: actions/checkout@v4 + - name: setup uv for tox + uses: yezz123/setup-uv@v4 + - name: setup python for tox + uses: actions/setup-python@v5 with: - fetch-depth: 0 - - name: Setup python for test ${{ matrix.py }} + python-version: "3.12" + - name: install tox + run: uv pip install tox tox-uv --system + - uses: actions/checkout@v4 + - name: setup python for test ${{ matrix.py }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.py }} - - name: Install tox - run: python -m pip install tox-uv - - name: Setup test suite - run: tox -e py -vv --notest - - name: Run test suite - run: tox -e py --skip-pkg-install - env: - PYTEST_ADDOPTS: "-vv --durations=20" + allow-prereleases: true + - name: setup test suite + run: tox run -vv --notest --skip-missing-interpreters false -e ${{ matrix.py }} + - name: run test suite + run: tox run --skip-pkg-install -e ${{ matrix.py }} check: name: tox env ${{ matrix.tox_env }} @@ -50,18 +54,18 @@ jobs: tox_env: - type - dev - - pkg_meta + - readme steps: + - name: setup uv for tox + uses: yezz123/setup-uv@v4 - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Python 3.12 + - name: setup Python 3.12 uses: actions/setup-python@v5 with: python-version: "3.12" - - name: Install tox - run: python -m pip install tox - - name: Run check for ${{ matrix.tox_env }} - run: tox -e ${{ matrix.tox_env }} - env: - UPGRADE_ADVISORY: "yes" + - name: install tox + run: uv pip install tox tox-uv --system + - name: Setup test suite + run: tox -vv --notest --skip-missing-interpreters false -e ${{ matrix.tox_env }} + - name: Run test suite + run: tox --skip-pkg-install -e ${{ matrix.tox_env }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ebafa51..bcac60f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest environment: name: release - url: https://pypi.org/p/pypi-changes + url: https://pypi.org/p/pytest-print permissions: id-token: write steps: @@ -16,12 +16,14 @@ jobs: uses: actions/setup-python@v5 with: python-version: "3.12" + - name: setup uv for tox + uses: yezz123/setup-uv@v4 - name: Install build - run: python -m pip install build + run: uv pip install build[uv] --system - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Build package - run: pyproject-build -s -w . -o dist + run: pyproject-build --installer uv --sdist --wheel . --outdir dist - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@v1.10.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 132b176..c46b622 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,14 +8,14 @@ repos: rev: 0.29.2 hooks: - id: check-github-workflows - args: [ "--verbose" ] + args: ["--verbose"] - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: - id: codespell additional_dependencies: ["tomli>=2.0.1"] - repo: https://github.com/tox-dev/tox-ini-fmt - rev: "1.3.1" + rev: "1.3.2" hooks: - id: tox-ini-fmt args: ["-p", "fix"] @@ -23,13 +23,17 @@ repos: rev: "2.2.1" hooks: - id: pyproject-fmt - additional_dependencies: ["tox>=4.13"] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.6.3" + rev: "v0.6.4" hooks: - id: ruff-format - id: ruff args: ["--fix", "--unsafe-fixes", "--exit-non-zero-on-fix"] + - repo: https://github.com/rbubley/mirrors-prettier + rev: "v3.3.3" + hooks: + - id: prettier + args: ["--print-width=120", "--prose-wrap=always"] - repo: meta hooks: - id: check-hooks-apply diff --git a/pyproject.toml b/pyproject.toml index b9c98d4..d7aebff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ build-backend = "hatchling.build" requires = [ "hatch-vcs>=0.4", - "hatchling>=1.21.1", + "hatchling>=1.25", ] [project] @@ -37,6 +37,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Testing", "Topic :: Utilities", @@ -45,22 +46,22 @@ dynamic = [ "version", ] dependencies = [ - "humanize>=4.9", - "packaging>=23.2", - "platformdirs>=4.2", - "pypi-simple>=1.5", - "requests>=2.31", - "requests-cache>=1.2", - "rich>=13.7", + "humanize>=4.10", + "packaging>=24.1", + "platformdirs>=4.3.1", + "pypi-simple>=1.6", + "requests>=2.32.3", + "requests-cache>=1.2.1", + "rich>=13.8", ] optional-dependencies.testing = [ "covdefaults>=2.3", - "pytest>=8.0.2", - "pytest-cov>=4.1", - "pytest-mock>=3.12", + "pytest>=8.3.2", + "pytest-cov>=5", + "pytest-mock>=3.14", "urllib3<2", "vcrpy>=6.0.1", - "virtualenv>=20.25.1", + "virtualenv>=20.26.4", ] urls.Homepage = "https://github.com/gaborbernat/pypi_changes" urls.Source = "https://github.com/gaborbernat/pypi_changes" @@ -74,30 +75,38 @@ version.source = "vcs" [tool.ruff] target-version = "py39" line-length = 120 -select = [ +format.preview = true +format.docstring-code-line-length = 100 +format.docstring-code-format = true +lint.select = [ "ALL", ] -isort = { known-first-party = [ - "pypi_changes", -], required-imports = [ - "from __future__ import annotations", -] } -ignore = [ - "CPY", # No copyright header - "INP001", # no implicit namespaces here +lint.ignore = [ "ANN101", # no type annotation for self "ANN401", # allow Any as type annotation + "COM812", # Conflict with formatter + "CPY", # No copyright statements "D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible "D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible + "DOC", # no support + "ISC001", # Conflict with formatter "S104", # Possible binding to all interface ] -per-file-ignores."tests/**/*.py" = [ - "S101", # asserts allowed in tests... +lint.per-file-ignores."tests/**/*.py" = [ + "D", # don't care about documentation in tests "FBT", # don't care about booleans as positional arguments in tests - "D", # don"t care about documentation in tests - "S603", # `subprocess` call: check for execution of untrusted input + "INP001", # no implicit namespace + "PLC2701", # allow private import "PLR2004", # Magic value used in comparison, consider replacing with a constant variable + "S101", # asserts allowed in testsā‰ˆ + "S603", # `subprocess` call: check for execution of untrusted input ] +lint.isort = { known-first-party = [ + "pypi_changes", +], required-imports = [ + "from __future__ import annotations", +] } +lint.preview = true [tool.codespell] builtin = "clear,usage,en-GB_to_en-US" @@ -105,6 +114,9 @@ write-changes = true count = true skip = "*.yaml" +[tool.pyproject-fmt] +max_supported_python = "3.13" + [tool.coverage] html.show_contexts = true html.skip_covered = false diff --git a/src/pypi_changes/_distributions.py b/src/pypi_changes/_distributions.py index df968fe..c245bb2 100644 --- a/src/pypi_changes/_distributions.py +++ b/src/pypi_changes/_distributions.py @@ -4,7 +4,7 @@ import re from importlib.metadata import Distribution, PathDistribution from pathlib import Path -from subprocess import check_output +from subprocess import check_output # noqa: S404 from typing import TYPE_CHECKING from rich.console import Console diff --git a/src/pypi_changes/_info.py b/src/pypi_changes/_info.py index d460faf..04732e3 100644 --- a/src/pypi_changes/_info.py +++ b/src/pypi_changes/_info.py @@ -62,7 +62,7 @@ class SpeedColumn(TextColumn): def __init__(self) -> None: super().__init__("[bold cyan]") - def render(self, task: Task) -> Text: + def render(self, task: Task) -> Text: # noqa: PLR6301 if task.speed is None: return Text("no speed") return Text(f"{task.speed:.3f} steps/s") @@ -135,6 +135,6 @@ def _merge_with_index_server( __all__ = [ - "pypi_info", "Package", + "pypi_info", ] diff --git a/src/pypi_changes/_pkg.py b/src/pypi_changes/_pkg.py index 3f96c66..b54f550 100644 --- a/src/pypi_changes/_pkg.py +++ b/src/pypi_changes/_pkg.py @@ -1,13 +1,13 @@ from __future__ import annotations from datetime import datetime, timezone -from typing import TYPE_CHECKING, Any +from pathlib import Path +from typing import TYPE_CHECKING, Any, cast from packaging.version import Version if TYPE_CHECKING: from importlib.metadata import PathDistribution - from pathlib import Path class Package: @@ -43,7 +43,7 @@ def version(self) -> str: @property def path(self) -> Path: - return self.dist._path # noqa: SLF001 + return cast(Path, self.dist._path) # noqa: SLF001 @property def current_release(self) -> dict[str, Any]: diff --git a/src/pypi_changes/_print/__init__.py b/src/pypi_changes/_print/__init__.py index 1ce9265..c4b373a 100644 --- a/src/pypi_changes/_print/__init__.py +++ b/src/pypi_changes/_print/__init__.py @@ -10,7 +10,7 @@ from pypi_changes._pkg import Package -class _Reversor: +class _Reversor: # noqa: PLW1641 def __init__(self, obj: str) -> None: self.obj = obj @@ -22,7 +22,7 @@ def __lt__(self, other: _Reversor) -> bool: def get_sorted_pkg_list(distributions: Iterable[Package], options: Options, now: datetime) -> Iterable[Package]: - if options.sort in ["a", "alphabetic"]: + if options.sort in {"a", "alphabetic"}: return sorted(distributions, key=lambda v: v.name.lower()) return sorted(distributions, key=lambda v: (v.last_release_at or now, _Reversor(v.name)), reverse=True) diff --git a/src/pypi_changes/_print/json.py b/src/pypi_changes/_print/json.py index 51e17b8..2b71938 100644 --- a/src/pypi_changes/_print/json.py +++ b/src/pypi_changes/_print/json.py @@ -1,4 +1,4 @@ -from __future__ import annotations +from __future__ import annotations # noqa: A005 import json from datetime import datetime, timezone diff --git a/tests/__init__.py b/tests/__init__.py index 74301af..d2ed7a0 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -8,6 +8,6 @@ MakeDist = Callable[[Path, str, str], MagicMock] __all__ = [ - "PathDistribution", "MakeDist", + "PathDistribution", ] diff --git a/tests/test_main.py b/tests/test_main.py index 1787f57..a22a65f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,6 +1,6 @@ from __future__ import annotations -import subprocess +import subprocess # noqa: S404 import sys from pathlib import Path diff --git a/tests/test_version.py b/tests/test_version.py index 017b3cd..9aeeb6b 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -2,6 +2,6 @@ def test_version() -> None: - from pypi_changes import __version__ + from pypi_changes import __version__ # noqa: PLC0415 assert __version__ diff --git a/tox.ini b/tox.ini index c2a6f53..d63fefe 100644 --- a/tox.ini +++ b/tox.ini @@ -3,12 +3,13 @@ requires = tox>=4.2 env_list = fix - py312 - py311 - py310 - py39 type - pkg_meta + readme + 3.13 + 3.12 + 3.11 + 3.10 + 3.9 skip_missing_interpreters = true [testenv] @@ -19,7 +20,6 @@ extras = testing pass_env = PYTEST_* - SSL_CERT_FILE set_env = COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}{/}.coverage.{envname}} COVERAGE_PROCESS_START = {toxinidir}{/}pyproject.toml @@ -35,7 +35,7 @@ commands = description = format the code base to adhere to our styles, and complain about what we cannot do automatically skip_install = true deps = - pre-commit>=3.6.2 + pre-commit>=3.8 pass_env = {[testenv]passenv} PROGRAMDATA @@ -45,23 +45,21 @@ commands = [testenv:type] description = run type check on code base deps = - mypy==1.8 - types-requests>=2.31.0.20240218 -set_env = - {tty:MYPY_FORCE_COLOR = 1} + mypy==1.11.2 + types-requests>=2.32.0.20240907 commands = mypy src/pypi_changes mypy tests -[testenv:pkg_meta] +[testenv:readme] description = check that the long description is valid skip_install = true deps = - build[virtualenv]>=1.0.3 + build[uv]>=1.2.2 check-wheel-contents>=0.6 - twine>=5 + twine>=5.1.1 commands = - python -m build -o {envtmpdir} -s -w . + pyproject-build --installer uv --outdir {envtmpdir} --sdist --wheel . twine check {envtmpdir}{/}* check-wheel-contents --no-config {envtmpdir} @@ -70,6 +68,5 @@ package = editable deps = {[testenv:type]deps} commands = - python -m pip list --format=columns + uv pip tree python -c "print(r'{envpython}')" -uv_seed = true