From cd08fcdc1c8c6cbb306ba1a245b9c5320d3509be Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 7 Oct 2026 12:14:25 -0400 Subject: [PATCH 1/5] feat: add Python 3.15 support Assisted-by: ClaudeCode:claude-opus-5-5 --- .github/workflows/reusable-rr-tests.yml | 2 +- AGENTS.md | 2 +- pyproject.toml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-rr-tests.yml b/.github/workflows/reusable-rr-tests.yml index eea335bb..c9cf2e60 100644 --- a/.github/workflows/reusable-rr-tests.yml +++ b/.github/workflows/reusable-rr-tests.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.12", "3.14"] + python-version: ["3.10", "3.12", "3.14", "3.15"] runs-on: [ubuntu-latest, macos-latest, macos-15-intel, windows-latest] steps: diff --git a/AGENTS.md b/AGENTS.md index c9bc9bd3..1c245906 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -67,7 +67,7 @@ The noxfile generates temporary projects for **all 9 backends** × **vcs on/off* - CI uses change detection to decide whether to run cookie tests or rr-tests. Both are required to pass for the `pass` job. -- rr-tests matrix runs on Python 3.10, 3.12, 3.14 across ubuntu/macos/windows. +- rr-tests matrix runs on Python 3.10, 3.12, 3.14, 3.15 across ubuntu/macos/windows. - Cookie tests reuse the same `reusable-cookie.yml` workflow. ## Docs site (MyST) diff --git a/pyproject.toml b/pyproject.toml index 4a708844..f27b30dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Programming Language :: Python", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", From 08aa763c63122412839208f79aead8a965bb02d4 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 7 Oct 2026 12:15:37 -0400 Subject: [PATCH 2/5] chore: drop Python 3.10 for sp-repo-review Assisted-by: ClaudeCode:claude-opus-5-5 --- .github/workflows/reusable-rr-tests.yml | 2 +- .pre-commit-config.yaml | 1 - AGENTS.md | 5 +++-- docs/guides/repo_review.md | 2 +- helpers/extensions.py | 2 +- pyproject.toml | 13 +++---------- src/sp_repo_review/_compat/__init__.py | 0 .../_compat/importlib/__init__.py | 0 .../_compat/importlib/resources/__init__.py | 0 .../_compat/importlib/resources/abc.py | 18 ------------------ src/sp_repo_review/_compat/tomllib.py | 16 ---------------- src/sp_repo_review/checks/general.py | 2 +- src/sp_repo_review/checks/github.py | 2 +- src/sp_repo_review/checks/noxfile.py | 6 +++--- src/sp_repo_review/checks/precommit.py | 2 +- src/sp_repo_review/checks/pyproject.py | 7 +++---- src/sp_repo_review/checks/readthedocs.py | 2 +- src/sp_repo_review/checks/ruff.py | 7 +++---- src/sp_repo_review/checks/setupcfg.py | 2 +- src/sp_repo_review/ruff_checks/__main__.py | 4 ++-- tests/test_general.py | 2 +- 21 files changed, 26 insertions(+), 69 deletions(-) delete mode 100644 src/sp_repo_review/_compat/__init__.py delete mode 100644 src/sp_repo_review/_compat/importlib/__init__.py delete mode 100644 src/sp_repo_review/_compat/importlib/resources/__init__.py delete mode 100644 src/sp_repo_review/_compat/importlib/resources/abc.py delete mode 100644 src/sp_repo_review/_compat/tomllib.py diff --git a/.github/workflows/reusable-rr-tests.yml b/.github/workflows/reusable-rr-tests.yml index c9cf2e60..a2e0e32f 100644 --- a/.github/workflows/reusable-rr-tests.yml +++ b/.github/workflows/reusable-rr-tests.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.12", "3.14", "3.15"] + python-version: ["3.11", "3.12", "3.14", "3.15"] runs-on: [ubuntu-latest, macos-latest, macos-15-intel, windows-latest] steps: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5399df55..f85bd287 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -50,7 +50,6 @@ repos: - nox - repo-review>=0.10.6 - rich - - tomli>=2.0.2 - types-PyYAML - repo: https://github.com/rbubley/mirrors-prettier diff --git a/AGENTS.md b/AGENTS.md index 1c245906..15ba0048 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -56,7 +56,7 @@ The noxfile generates temporary projects for **all 9 backends** × **vcs on/off* directory. - `tool.ruff.extend-exclude` also excludes `\{\{cookiecutter.project_name\}\}` (double-escaped in TOML). -- `tool.mypy.python_version = "3.10"`; the `sp_repo_review.*` override enforces +- `tool.mypy.python_version = "3.11"`; the `sp_repo_review.*` override enforces `disallow_untyped_defs=True`. - `tool.pylint.master.ignore-paths` ignores `src/sp_repo_review/_version.py` (auto-generated by hatch-vcs). @@ -67,7 +67,8 @@ The noxfile generates temporary projects for **all 9 backends** × **vcs on/off* - CI uses change detection to decide whether to run cookie tests or rr-tests. Both are required to pass for the `pass` job. -- rr-tests matrix runs on Python 3.10, 3.12, 3.14, 3.15 across ubuntu/macos/windows. +- rr-tests matrix runs on Python 3.11, 3.12, 3.14, 3.15 across + ubuntu/macos/windows. - Cookie tests reuse the same `reusable-cookie.yml` workflow. ## Docs site (MyST) diff --git a/docs/guides/repo_review.md b/docs/guides/repo_review.md index b3e72e32..79cdca08 100644 --- a/docs/guides/repo_review.md +++ b/docs/guides/repo_review.md @@ -9,7 +9,7 @@ fail, that's okay - the goal is bring all possible issues to your attention, not to force compliance with arbitrary checks. You can also run [this tool](https://github.com/scientific-python/repo-review) -locally (Python 3.10+ required): +locally (Python 3.11+ required): ```bash pipx run 'sp-repo-review[cli]' diff --git a/helpers/extensions.py b/helpers/extensions.py index eff35be8..212f549f 100644 --- a/helpers/extensions.py +++ b/helpers/extensions.py @@ -39,7 +39,7 @@ class CookiecutterContext(SmartDict): @CookiecutterContext.register def __year(_): - return str(datetime.datetime.now(tz=datetime.timezone.utc).year) + return str(datetime.datetime.now(tz=datetime.UTC).year) @CookiecutterContext.register diff --git a/pyproject.toml b/pyproject.toml index f27b30dc..7a8b1e23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ authors = [ { name = "Henry Schreiner", email = "henryfs@princeton.edu" }, ] description = "Review repos for compliance to the Scientific-Python development guidelines" -requires-python = ">=3.10" +requires-python = ">=3.11" license = "BSD-3-Clause" classifiers = [ "Development Status :: 4 - Beta", @@ -19,7 +19,6 @@ classifiers = [ "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", @@ -35,7 +34,6 @@ dynamic = ["version", "readme"] dependencies = [ "pyyaml", "repo-review", - "tomli; python_version<'3.11'", ] [project.optional-dependencies] @@ -135,7 +133,7 @@ testpaths = ["tests"] [tool.mypy] mypy_path = ["src"] files = ["src", "tests"] -python_version = "3.10" +python_version = "3.11" warn_unused_configs = true strict = true enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] @@ -150,7 +148,7 @@ disallow_incomplete_defs = true [tool.pylint] -master.py-version = "3.10" +master.py-version = "3.11" master.ignore-paths= ["src/sp_repo_review/_version.py"] reports.output-format = "colorized" similarities.ignore-imports = "yes" @@ -193,12 +191,7 @@ ignore = [ "TID252", # Relative imports are fine ] -[tool.ruff.lint.flake8-tidy-imports.banned-api] -"importlib.abc".msg = "Use sp_repo_review._compat.importlib.resources.abc instead." -"importlib.resources.abc".msg = "Use sp_repo_review._compat.importlib.resources.abc instead." - [tool.ruff.lint.per-file-ignores] -"src/sp_repo_review/_compat/**.py" = ["TID251"] "src/sp_repo_review/checks/*.py" = ["ERA001"] "src/sp_repo_review/ruff_checks/__main__.py" = ["PLC0415", "T20"] "tests/**" = ["ANN", "INP001", "S607"] diff --git a/src/sp_repo_review/_compat/__init__.py b/src/sp_repo_review/_compat/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/sp_repo_review/_compat/importlib/__init__.py b/src/sp_repo_review/_compat/importlib/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/sp_repo_review/_compat/importlib/resources/__init__.py b/src/sp_repo_review/_compat/importlib/resources/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/sp_repo_review/_compat/importlib/resources/abc.py b/src/sp_repo_review/_compat/importlib/resources/abc.py deleted file mode 100644 index 59f4b8d1..00000000 --- a/src/sp_repo_review/_compat/importlib/resources/abc.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import annotations - -__lazy_modules__ = ["importlib", "importlib.resources", "importlib.resources.abc"] - -import sys - -if sys.version_info < (3, 11): - # pylint: disable-next=deprecated-class - from importlib.abc import Traversable -else: - from importlib.resources.abc import Traversable - - -__all__ = ["Traversable"] - - -def __dir__() -> list[str]: - return __all__ diff --git a/src/sp_repo_review/_compat/tomllib.py b/src/sp_repo_review/_compat/tomllib.py deleted file mode 100644 index 04ad48f9..00000000 --- a/src/sp_repo_review/_compat/tomllib.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import annotations - -__lazy_modules__ = ["tomllib"] - -import sys - -if sys.version_info < (3, 11): - from tomli import load, loads -else: - from tomllib import load, loads - -__all__ = ["load", "loads"] - - -def __dir__() -> list[str]: - return __all__ diff --git a/src/sp_repo_review/checks/general.py b/src/sp_repo_review/checks/general.py index c8ecdcc1..1f1bec77 100644 --- a/src/sp_repo_review/checks/general.py +++ b/src/sp_repo_review/checks/general.py @@ -5,7 +5,7 @@ from . import mk_url if TYPE_CHECKING: - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable # PY: Python Project ## 0xx: File existence diff --git a/src/sp_repo_review/checks/github.py b/src/sp_repo_review/checks/github.py index 1547b238..df36445f 100644 --- a/src/sp_repo_review/checks/github.py +++ b/src/sp_repo_review/checks/github.py @@ -13,7 +13,7 @@ from . import mk_url if TYPE_CHECKING: - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable def workflows(root: Traversable) -> dict[str, Any]: diff --git a/src/sp_repo_review/checks/noxfile.py b/src/sp_repo_review/checks/noxfile.py index 011a50ee..bf2d088c 100644 --- a/src/sp_repo_review/checks/noxfile.py +++ b/src/sp_repo_review/checks/noxfile.py @@ -4,18 +4,18 @@ from __future__ import annotations -__lazy_modules__ = ["ast", f"{__spec__.parent.rsplit('.', 1)[0]}._compat"] # type: ignore[union-attr] +__lazy_modules__ = ["ast", "tomllib"] import ast import dataclasses import re +import tomllib from typing import TYPE_CHECKING, Any -from .._compat import tomllib from . import mk_url if TYPE_CHECKING: - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable REGEX = re.compile( r"(?m)^# /// (?P[a-zA-Z0-9-]+)$\s(?P(^#(| .*)$\s)+)^# ///$" diff --git a/src/sp_repo_review/checks/precommit.py b/src/sp_repo_review/checks/precommit.py index fb0b14b6..8d751755 100644 --- a/src/sp_repo_review/checks/precommit.py +++ b/src/sp_repo_review/checks/precommit.py @@ -12,7 +12,7 @@ from . import mk_url if TYPE_CHECKING: - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable def precommit(root: Traversable) -> dict[str, Any]: diff --git a/src/sp_repo_review/checks/pyproject.py b/src/sp_repo_review/checks/pyproject.py index 92182039..0cd3f17b 100644 --- a/src/sp_repo_review/checks/pyproject.py +++ b/src/sp_repo_review/checks/pyproject.py @@ -1,17 +1,16 @@ from __future__ import annotations -__lazy_modules__ = [f"{__spec__.parent.rsplit('.', 1)[0]}._compat"] # type: ignore[union-attr] +__lazy_modules__ = ["tomllib"] import enum +import tomllib from typing import TYPE_CHECKING, Any -from .._compat import tomllib from . import mk_url if TYPE_CHECKING: from configparser import ConfigParser - - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable class PytestFile(enum.Enum): diff --git a/src/sp_repo_review/checks/readthedocs.py b/src/sp_repo_review/checks/readthedocs.py index eb3a9230..ff389259 100644 --- a/src/sp_repo_review/checks/readthedocs.py +++ b/src/sp_repo_review/checks/readthedocs.py @@ -9,7 +9,7 @@ from . import mk_url if TYPE_CHECKING: - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable class ReadTheDocs: diff --git a/src/sp_repo_review/checks/ruff.py b/src/sp_repo_review/checks/ruff.py index 8122c0e3..702f3658 100644 --- a/src/sp_repo_review/checks/ruff.py +++ b/src/sp_repo_review/checks/ruff.py @@ -1,16 +1,15 @@ from __future__ import annotations -__lazy_modules__ = [f"{__spec__.parent.rsplit('.', 1)[0]}._compat"] # type: ignore[union-attr] +__lazy_modules__ = ["tomllib"] +import tomllib from typing import TYPE_CHECKING, Any, ClassVar, Literal, Protocol -from .._compat import tomllib from . import mk_url if TYPE_CHECKING: from collections.abc import Generator - - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable ## R0xx: Ruff general ## R1xx: Ruff checks diff --git a/src/sp_repo_review/checks/setupcfg.py b/src/sp_repo_review/checks/setupcfg.py index dba452ba..a08e7ec1 100644 --- a/src/sp_repo_review/checks/setupcfg.py +++ b/src/sp_repo_review/checks/setupcfg.py @@ -11,7 +11,7 @@ from . import mk_url if TYPE_CHECKING: - from .._compat.importlib.resources.abc import Traversable + from importlib.resources.abc import Traversable def setupcfg(root: Traversable) -> configparser.ConfigParser | None: diff --git a/src/sp_repo_review/ruff_checks/__main__.py b/src/sp_repo_review/ruff_checks/__main__.py index 3b294162..05814ae0 100644 --- a/src/sp_repo_review/ruff_checks/__main__.py +++ b/src/sp_repo_review/ruff_checks/__main__.py @@ -4,7 +4,7 @@ "collections.abc", "os", "pathlib", - "sp_repo_review._compat", + "tomllib", "sp_repo_review.checks", "sp_repo_review.checks.ruff", "sys", @@ -17,11 +17,11 @@ import json import os import sys +import tomllib from collections.abc import Iterator, Mapping from importlib.util import find_spec from pathlib import Path -from sp_repo_review._compat import tomllib from sp_repo_review.checks.ruff import get_rule_selection, ruff # Create using ruff linter --output-format=json > src/sp_repo_review/ruff/linter.json diff --git a/tests/test_general.py b/tests/test_general.py index 8de75dcb..761c1f7d 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -1,9 +1,9 @@ +import tomllib from pathlib import Path import pytest from repo_review.testing import compute_check -from sp_repo_review._compat import tomllib from sp_repo_review.checks.general import PY007_VALID_RUNNER_CONFS From 0f36e17891dbc4a6f54d5d06562d01bf8f75918d Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 7 Oct 2026 12:19:05 -0400 Subject: [PATCH 3/5] chore: drop Python 3.10 from template and guide Assisted-by: ClaudeCode:claude-opus-5-5 --- .github/workflows/reusable-cookie.yml | 2 +- README.md | 2 +- docs/_partials/pyproject.md | 3 +-- docs/guides/gha_basic.md | 2 +- docs/guides/packaging_compiled.md | 4 ++-- docs/guides/style.md | 10 +++++----- docs/guides/tasks.md | 4 ++-- {{cookiecutter.project_name}}/.github/workflows/ci.yml | 2 +- {{cookiecutter.project_name}}/pyproject.toml | 7 +++---- ...iecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} | 6 +++--- ...iecutter.backend=='maturin' %}Cargo.toml{% endif %} | 4 ++-- 11 files changed, 22 insertions(+), 24 deletions(-) diff --git a/.github/workflows/reusable-cookie.yml b/.github/workflows/reusable-cookie.yml index 760dadd0..60dcd432 100644 --- a/.github/workflows/reusable-cookie.yml +++ b/.github/workflows/reusable-cookie.yml @@ -26,7 +26,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.14"] + python-version: ["3.11", "3.14"] runs-on: [ubuntu-latest, windows-latest, macos-latest, macos-15-intel] include: diff --git a/README.md b/README.md index a4aebb56..a3627226 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Check the key setup files, `pyproject.toml`, and possibly `setup.cfg` and `setup.py` (pybind11 example). Update `README.md`. Also update and add docs to `docs/`. -There are a few example dependencies and a minimum Python version of 3.10, feel +There are a few example dependencies and a minimum Python version of 3.11, feel free to change it to whatever you actually need/want. There is also a basic backports structure with a small typing example. diff --git a/docs/_partials/pyproject.md b/docs/_partials/pyproject.md index afc33705..bb76f6a6 100644 --- a/docs/_partials/pyproject.md +++ b/docs/_partials/pyproject.md @@ -27,7 +27,7 @@ description = "A great package." readme = "README.md" license = "BSD-3-Clause" license-files = ["LICENSE"] -requires-python = ">=3.10" +requires-python = ">=3.11" classifiers = [ "Development Status :: 1 - Planning", "Intended Audience :: Science/Research", @@ -36,7 +36,6 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", diff --git a/docs/guides/gha_basic.md b/docs/guides/gha_basic.md index 2cce0ff6..be2c6826 100644 --- a/docs/guides/gha_basic.md +++ b/docs/guides/gha_basic.md @@ -106,7 +106,7 @@ tests: fail-fast: false matrix: python-version: - - "3.10" + - "3.11" - "3.12" - "3.14" name: Check Python ${{ matrix.python-version }} diff --git a/docs/guides/packaging_compiled.md b/docs/guides/packaging_compiled.md index a3ff61b2..e5747082 100644 --- a/docs/guides/packaging_compiled.md +++ b/docs/guides/packaging_compiled.md @@ -260,8 +260,8 @@ rand = "0.9.2" [dependencies.pyo3] version = "0.27.2" # "extension-module" tells pyo3 we want to build an extension module (skips linking against libpython.so) -# "abi3-py310" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.10 -features = ["extension-module", "abi3-py310"] +# "abi3-py311" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.11 +features = ["extension-module", "abi3-py311"] ``` diff --git a/docs/guides/style.md b/docs/guides/style.md index f8aec28c..25a508c7 100644 --- a/docs/guides/style.md +++ b/docs/guides/style.md @@ -382,7 +382,7 @@ If you don't use a `[project]` table (older setuptools or Poetry), then you should also set: ```ini -target-version = "py310" +target-version = "py311" ``` This selects the minimum version you want to target (primarily for `"UP"` and @@ -701,7 +701,7 @@ this: ```ini [tool.mypy] files = "src" -python_version = "3.10" +python_version = "3.11" strict = true enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] warn_unreachable = true @@ -737,7 +737,7 @@ errors in your typing. ```toml [tool.pyrefly] project-includes = ["src"] -python-version = "3.10" +python-version = "3.11" project-excludes = ["**/tests"] # Use `Any` for imports that can't be resolved, one entry per module @@ -768,7 +768,7 @@ You can disable Pyrefly on a line with `# pyrefly: ignore` (or ```toml [tool.ty.environment] -python-version = "3.10" +python-version = "3.11" [tool.ty.src] include = ["src"] @@ -1086,7 +1086,7 @@ started: ```ini [tool.pylint] -py-version = "3.10" +py-version = "3.11" jobs = "0" reports.output-format = "colorized" similarities.ignore-imports = "yes" diff --git a/docs/guides/tasks.md b/docs/guides/tasks.md index c12e1f67..c354381d 100644 --- a/docs/guides/tasks.md +++ b/docs/guides/tasks.md @@ -76,7 +76,7 @@ customize the versions of Python prepared for you, then use input like this: ```yaml - uses: wntrblm/nox@2026.08.17 with: - python-versions: "3.10, 3.11, 3.12, 3.13, 3.13t, 3.14, 3.14t, pypy-3.11" + python-versions: "3.11, 3.12, 3.13, 3.13t, 3.14, 3.14t, pypy-3.11" ``` ### Introduction @@ -127,7 +127,7 @@ You can parametrize sessions. either on Python or on any other item. ```python # Shortcut to parametrize Python -@nox.session(python=["3.10", "3.11", "3.12", "3.13", "3.14"]) +@nox.session(python=["3.11", "3.12", "3.13", "3.14"]) def my_session(session: nox.Session) -> None: ... diff --git a/{{cookiecutter.project_name}}/.github/workflows/ci.yml b/{{cookiecutter.project_name}}/.github/workflows/ci.yml index 819786a4..2fa22ac4 100644 --- a/{{cookiecutter.project_name}}/.github/workflows/ci.yml +++ b/{{cookiecutter.project_name}}/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.14"] + python-version: ["3.11", "3.14"] runs-on: [ubuntu-latest, windows-latest, macos-latest, macos-15-intel] include: diff --git a/{{cookiecutter.project_name}}/pyproject.toml b/{{cookiecutter.project_name}}/pyproject.toml index 3a1013e8..d7d121d1 100644 --- a/{{cookiecutter.project_name}}/pyproject.toml +++ b/{{cookiecutter.project_name}}/pyproject.toml @@ -79,7 +79,7 @@ license = "MIT" {%- endif %} license-files = ["LICENSE"] {%- endif %} -requires-python = ">=3.10" +requires-python = ">=3.11" classifiers = [ "Development Status :: 1 - Planning", "Intended Audience :: Science/Research", @@ -97,7 +97,6 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", @@ -267,7 +266,7 @@ report.exclude_also = [ [tool.mypy] files = ["src", "tests"] -python_version = "3.10" +python_version = "3.11" warn_unused_configs = true strict = true enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] @@ -332,7 +331,7 @@ ignore = [ [tool.pylint] -py-version = "3.10" +py-version = "3.11" ignore-paths = [".*/_version.py"] {%- if cookiecutter.__type == "compiled" %} extension-pkg-allow-list = ["{{ cookiecutter.__project_slug }}._core"] diff --git a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} index 452f7ca5..2ba17a84 100644 --- a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} +++ b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} @@ -14,7 +14,7 @@ cache: - .cache/pip - .venv/ -image: python:3.10-buster +image: python:3.11-bookworm before_script: # want to set up a virtualenv to cache - apt-get install -y --no-install-recommends git @@ -79,7 +79,7 @@ tests: - python -m pytest -ra --cov={{ cookiecutter.project_name }} parallel: matrix: - - IMAGE: ['python:3.10-buster', 'python:3.11-buster'] + - IMAGE: ['python:3.11-bookworm', 'python:3.14-bookworm'] {%- if cookiecutter.__type == "pure" %} @@ -121,7 +121,7 @@ make_wheels: entrypoint: ["env", "-u", "DOCKER_HOST"] command: ["dockerd-entrypoint.sh"] matrix: - - CIBW_BUILD: ['cp39-*', 'cp310-*', 'cp311-*', 'cp312-*', 'cp313-*'] + - CIBW_BUILD: ['cp311-*', 'cp312-*', 'cp313-*', 'cp314-*'] CIBW_PLATFORM: ['linux', 'windows'] # 'macos' not supported by CIBW on GitLab CI variables: DOCKER_HOST: tcp://docker:2375/ diff --git a/{{cookiecutter.project_name}}/{% if cookiecutter.backend=='maturin' %}Cargo.toml{% endif %} b/{{cookiecutter.project_name}}/{% if cookiecutter.backend=='maturin' %}Cargo.toml{% endif %} index 002d305c..ff1040f6 100644 --- a/{{cookiecutter.project_name}}/{% if cookiecutter.backend=='maturin' %}Cargo.toml{% endif %} +++ b/{{cookiecutter.project_name}}/{% if cookiecutter.backend=='maturin' %}Cargo.toml{% endif %} @@ -14,5 +14,5 @@ rand = "0.9.2" [dependencies.pyo3] version = "0.27.2" # "extension-module" tells pyo3 we want to build an extension module (skips linking against libpython.so) -# "abi3-py310" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.10 -features = ["extension-module", "abi3-py310"] +# "abi3-py311" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.11 +features = ["extension-module", "abi3-py311"] From 1bf929379851763262b210f15c96989c41c2c5f4 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 7 Oct 2026 12:23:45 -0400 Subject: [PATCH 4/5] chore: drop codespell tomli dependency and fix nox session names in AGENTS.md Assisted-by: ClaudeCode:claude-opus-5-5 --- AGENTS.md | 17 ++++++++++------- docs/guides/style.md | 2 -- .../.pre-commit-config.yaml | 2 -- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 15ba0048..8350f3b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,13 +22,16 @@ Important: tests run with `PYTHONWARNDEFAULTENCODING=1`. ### Cookie template validation -The noxfile generates temporary projects for **all 9 backends** × **vcs on/off** -× **3 docs engines** (sphinx/properdocs/zensical). These are slow. - -- `nox -s "tests(hatch)"` — run generated project tests for a single backend -- `nox -s "lint(hatch)"` — run pre-commit (`prek`) on generated project -- `nox -s "dist(hatch)"` — verify build output includes LICENSE -- `nox -s "native(hatch)"` — test hatch/pdm/poetry native test runners +The noxfile generates temporary projects for **all 10 backends** × **vcs +on/off** × **3 docs engines** (sphinx/properdocs/zensical). These are slow. +Session names include all three, like `tests(hatch, vcs, sphinx)`. + +- `nox -s "tests(hatch, vcs, sphinx)"` — run generated project tests +- `nox -s "lint(hatch, vcs, sphinx)"` — run pre-commit (`prek`) on generated + project +- `nox -s "dist(hatch, vcs, sphinx)"` — verify build output includes LICENSE +- `nox -s "native(hatch, vcs, sphinx)"` — test hatch/pdm/poetry native test + runners - `nox -s compare_copier` — verify cookiecutter and copier produce identical files - `nox -s compare_cruft` — verify cookiecutter and cruft produce identical files diff --git a/docs/guides/style.md b/docs/guides/style.md index 25a508c7..3da2b595 100644 --- a/docs/guides/style.md +++ b/docs/guides/style.md @@ -882,8 +882,6 @@ If you want a Python based tool, [codespell] is the classic tool used. rev: "v2.4.3" hooks: - id: codespell - additional_dependencies: - - tomli; python_version<'3.11' ``` You can list allowed spellings in a comma separated string passed to `-L` (or diff --git a/{{cookiecutter.project_name}}/.pre-commit-config.yaml b/{{cookiecutter.project_name}}/.pre-commit-config.yaml index 6a1218c3..e5728c31 100644 --- a/{{cookiecutter.project_name}}/.pre-commit-config.yaml +++ b/{{cookiecutter.project_name}}/.pre-commit-config.yaml @@ -68,8 +68,6 @@ repos: rev: "v2.4.3" hooks: - id: codespell - additional_dependencies: - - tomli; python_version<'3.11' - repo: https://github.com/shellcheck-py/shellcheck-py rev: "v0.11.0.1-1" From 56a48d71ef6d14b08b80429aff69aab15494cf91 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 7 Oct 2026 12:31:31 -0400 Subject: [PATCH 5/5] Apply suggestion from @henryiii --- .github/workflows/reusable-rr-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-rr-tests.yml b/.github/workflows/reusable-rr-tests.yml index a2e0e32f..ddf6ef99 100644 --- a/.github/workflows/reusable-rr-tests.yml +++ b/.github/workflows/reusable-rr-tests.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.11", "3.12", "3.14", "3.15"] + python-version: ["3.11", "3.13", "3.15"] runs-on: [ubuntu-latest, macos-latest, macos-15-intel, windows-latest] steps: