From 144fb90935e83197567b041898855a87614206bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 9 Oct 2026 15:42:31 -0700 Subject: [PATCH 1/5] feat(python): default to Python 3.15 --- .github/workflows/check.yaml | 9 +++---- .github/workflows/release.yaml | 2 +- .pre-commit-config.yaml | 3 ++- .readthedocs.yml | 2 +- docs/conf.py | 4 +-- pyproject.toml | 45 +++++++++++++++++----------------- tox.toml | 9 ++++--- 7 files changed, 38 insertions(+), 36 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 7b7b298c..31dbc4e0 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -27,7 +27,6 @@ jobs: - "3.13" - "3.12" - "3.11" - - "3.10" os: - ubuntu-24.04 - windows-2025 @@ -44,7 +43,7 @@ jobs: with: enable-cache: false - name: Install tox - run: uv tool install --python-preference only-managed --python 3.14 tox --with tox-uv + run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv - name: Install Python run: uv python install --python-preference only-managed ${{ matrix.py }} - name: Setup test suite @@ -99,9 +98,9 @@ jobs: with: enable-cache: false - name: Install tox - run: uv tool install --python-preference only-managed --python 3.14 tox --with tox-uv + run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv - name: Build package to generate version - run: uv build --python 3.14 --python-preference only-managed --wheel . --out-dir dist + run: uv build --python 3.15 --python-preference only-managed --wheel . --out-dir dist - name: Setup coverage tool run: tox -e coverage --notest env: @@ -142,7 +141,7 @@ jobs: with: enable-cache: false - name: Install tox - run: uv tool install --python-preference only-managed --python 3.14 tox --with tox-uv + run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv - name: Setup test suite run: tox run -vv --notest --skip-missing-interpreters false -e ${{ matrix.tox_env }} env: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index fb4a62a3..197ae5a9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -28,7 +28,7 @@ jobs: with: enable-cache: false # this workflow builds the artifact that gets published; no cache to poison - name: 📦 Build package - run: uv build --python 3.14 --python-preference only-managed --sdist --wheel . --out-dir dist + run: uv build --python 3.15 --python-preference only-managed --sdist --wheel . --out-dir dist - name: 📤 Store the distribution packages uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1bacc348..6a0dee2d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,5 @@ +default_language_version: + python: python3.15 repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 @@ -13,7 +15,6 @@ repos: rev: v2.4.3 hooks: - id: codespell - additional_dependencies: ["tomli>=2.4"] - repo: https://github.com/tox-dev/tox-toml-fmt rev: "v1.11.0" hooks: diff --git a/.readthedocs.yml b/.readthedocs.yml index af60a61c..bc539b4d 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,7 +2,7 @@ version: 2 build: os: ubuntu-lts-latest tools: - python: "3" + python: "3.15" commands: - pip install uv - uv venv diff --git a/docs/conf.py b/docs/conf.py index 9bbbbfba..4e98c32b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,7 +4,7 @@ from __future__ import annotations import os -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from platformdirs.version import __version__ @@ -32,7 +32,7 @@ ] html_theme = "furo" html_logo = html_favicon = "platformdirs.svg" -html_title, html_last_updated_fmt = "platformdirs", datetime.now(tz=timezone.utc).isoformat() +html_title, html_last_updated_fmt = "platformdirs", datetime.now(tz=UTC).isoformat() pygments_style, pygments_dark_style = "sphinx", "monokai" autoclass_content, autodoc_member_order, autodoc_typehints = "class", "bysource", "none" autodoc_default_options = { diff --git a/pyproject.toml b/pyproject.toml index 32581a7a..d3279820 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ maintainers = [ { name = "Ofek Lev", email = "oss@ofek.dev" }, { name = "Ronny Pfannschmidt", email = "opensource@ronnypfannschmidt.de" }, ] -requires-python = ">=3.10" +requires-python = ">=3.11" classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -32,7 +32,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "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", @@ -121,28 +120,28 @@ lint.select = [ "ALL", ] lint.ignore = [ - "COM812", # conflict - "CPY", # no copyright notices - "D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible - "D205", # 1 blank line required between summary line and description - "D213", # `multi-line-summary-second-line` (D213) conflicts with docstrfmt which uses D212 style - "D301", # Use `r"""` if any backslashes in a docstring - "D401", # The first line of docstring should be in imperative mood - "DOC", # no support for restructuredtext - "E501", # line length handled by ruff format (code) and docstrfmt (docstrings) - "RUF067", # `__init__` module should only contain docstrings and re-exports - "S104", # Possible binding to all interfaces + "CPY", # no copyright notices + "DOC", # no support for restructuredtext + "escape-sequence-in-docstring", # Use `r"""` if any backslashes in a docstring + "hardcoded-bind-all-interfaces", # Possible binding to all interfaces + "incorrect-blank-line-before-class", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible + "line-too-long", # line length handled by ruff format (code) and docstrfmt (docstrings) + "missing-blank-line-after-summary", # 1 blank line required between summary line and description + "missing-trailing-comma", # conflict + "multi-line-summary-second-line", # `multi-line-summary-second-line` (D213) conflicts with docstrfmt which uses D212 style + "non-empty-init-module", # `__init__` module should only contain docstrings and re-exports + "non-imperative-mood", # The first line of docstring should be in imperative mood ] 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 - "INP001", # no implicit namespace - "PLC2701", # Private name import - "PLR0917", # Too many positional arguments - "PLR2004", # Magic value used in comparison, consider replacing with a constant variable - "pytest-fixture-autouse", # shared setup fixtures are meant to apply to every test - "S101", # asserts allowed in tests - "S603", # `subprocess` call: check for execution of untrusted input + "assert", # asserts allowed in tests + "D", # don't care about documentation in tests + "FBT", # don't care about booleans as positional arguments in tests + "implicit-namespace-package", # no implicit namespace + "import-private-name", # Private name import + "magic-value-comparison", # Magic value used in comparison, consider replacing with a constant variable + "pytest-fixture-autouse", # shared setup fixtures are meant to apply to every test + "subprocess-without-shell-equals-true", # `subprocess` call: check for execution of untrusted input + "too-many-positional-arguments", # Too many positional arguments ] lint.isort = { known-first-party = [ "platformdirs", @@ -161,7 +160,7 @@ quiet-level = 3 max_supported_python = "3.15" [tool.ty] -environment.python-version = "3.14" +environment.python-version = "3.15" [tool.coverage] run.parallel = true diff --git a/tox.toml b/tox.toml index 6dd9ac62..512f9f81 100644 --- a/tox.toml +++ b/tox.toml @@ -1,11 +1,10 @@ -requires = [ "tox>=4.47" ] +requires = [ "tox>=4.64.7" ] env_list = [ "3.15", "3.14", "3.13", "3.12", "3.11", - "3.10", "pypy3.11", "3.15t", "coverage", @@ -18,6 +17,7 @@ skip_missing_interpreters = true [env_run_base] description = "run the tests with pytest under {env_name}" +default_base_python = [ "3.15" ] package = "wheel" wheel_build_env = ".pkg" dependency_groups = [ "test" ] @@ -59,6 +59,9 @@ commands = [ ], extend = true }, ] +[env_pkg_base] +default_base_python = [ "3.15" ] + [env.coverage] description = "combine coverage files and generate diff (against DIFF_AGAINST defaulting to origin/main)" skip_install = true @@ -84,7 +87,7 @@ commands = [ "{env_tmp_dir}{/}coverage.xml", ], ] -depends = [ "3.10", "3.11", "3.12", "3.13", "3.14", "3.15", "pypy3.11" ] +depends = [ "3.11", "3.12", "3.13", "3.14", "3.15", "pypy3.11" ] [env.docs] description = "build documentation" From 5188a1011179eb7fe3313f07647997531e9019fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 9 Oct 2026 16:01:32 -0700 Subject: [PATCH 2/5] fix(docs): install Python 3.15 with uv --- .readthedocs.yml | 10 ++++------ docs/changelog/613.breaking.rst | 1 + docs/changelog/613.packaging.rst | 1 + 3 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 docs/changelog/613.breaking.rst create mode 100644 docs/changelog/613.packaging.rst diff --git a/.readthedocs.yml b/.readthedocs.yml index bc539b4d..84f75c67 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,10 +1,8 @@ version: 2 build: os: ubuntu-lts-latest - tools: - python: "3.15" + tools: {} commands: - - pip install uv - - uv venv - - uv pip install tox-uv - - .venv/bin/tox run -e docs -- + - curl -LsSf https://astral.sh/uv/install.sh | sh + - ~/.local/bin/uv tool install tox --with tox-uv -p 3.15 --managed-python + - ~/.local/bin/tox run -e docs -- diff --git a/docs/changelog/613.breaking.rst b/docs/changelog/613.breaking.rst new file mode 100644 index 00000000..56163712 --- /dev/null +++ b/docs/changelog/613.breaking.rst @@ -0,0 +1 @@ +Require Python 3.11 or newer. diff --git a/docs/changelog/613.packaging.rst b/docs/changelog/613.packaging.rst new file mode 100644 index 00000000..a6350e6f --- /dev/null +++ b/docs/changelog/613.packaging.rst @@ -0,0 +1 @@ +Use Python 3.15 for development and automation. From 6233dc3906e01e17ba3f985e96bfdf920aa6b759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 9 Oct 2026 16:14:49 -0700 Subject: [PATCH 3/5] feat(ci): default uv to Python 3.15 --- .github/workflows/check.yaml | 10 +++++++--- .github/workflows/prepare-release.yaml | 1 + .github/workflows/release.yaml | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 31dbc4e0..5ea3973f 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -41,6 +41,7 @@ jobs: - name: Install the latest version of uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 with: + python-version: "3.15" enable-cache: false - name: Install tox run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv @@ -70,7 +71,7 @@ jobs: shell: python - name: Upload coverage data if: ${{ !startsWith(matrix.py, 'pypy')}} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: include-hidden-files: true name: .coverage.${{ matrix.os }}.${{ matrix.py }} @@ -88,7 +89,7 @@ jobs: - name: Download coverage data id: coverage-data background: true - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: .tox pattern: .coverage.* @@ -96,6 +97,7 @@ jobs: - name: Install the latest version of uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 with: + python-version: "3.15" enable-cache: false - name: Install tox run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv @@ -111,7 +113,7 @@ jobs: env: UV_PYTHON_PREFERENCE: only-managed - name: Upload HTML report - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: html-report path: .tox/htmlcov @@ -139,6 +141,7 @@ jobs: - name: Install the latest version of uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 with: + python-version: "3.15" enable-cache: false - name: Install tox run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv @@ -165,6 +168,7 @@ jobs: - name: Install the latest version of uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 with: + python-version: "3.15" enable-cache: false - name: Require a news fragment run: uvx towncrier check --compare-with "origin/${GITHUB_BASE_REF}" diff --git a/.github/workflows/prepare-release.yaml b/.github/workflows/prepare-release.yaml index 4c31ba96..ecca6799 100644 --- a/.github/workflows/prepare-release.yaml +++ b/.github/workflows/prepare-release.yaml @@ -28,6 +28,7 @@ jobs: - name: 📦 Setup uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 with: + python-version: "3.15" enable-cache: false - name: 🔢 Compute next version id: version diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 197ae5a9..96cc6a44 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -26,11 +26,12 @@ jobs: - name: 📦 Setup uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 with: + python-version: "3.15" enable-cache: false # this workflow builds the artifact that gets published; no cache to poison - name: 📦 Build package run: uv build --python 3.15 --python-preference only-managed --sdist --wheel . --out-dir dist - name: 📤 Store the distribution packages - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ env.dists-artifact-name }} path: dist/* @@ -61,7 +62,7 @@ jobs: exit 1 fi - name: ⬇️ Download all the dists - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: ${{ env.dists-artifact-name }} path: dist/ From 9f9b3a51455ff52f59b0d48c4530da95ed3522c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 9 Oct 2026 17:03:19 -0700 Subject: [PATCH 4/5] fix(ci): isolate Proselint on Python 3.14 --- pyproject.toml | 2 +- tox.toml | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d3279820..0a145e6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,6 @@ type = [ ] docs = [ "furo>=2025.12.19", - "proselint>=0.16", "sphinx>=9.1", "sphinx-autodoc-typehints>=3.9.2", "sphinx-copybutton>=0.5.2", @@ -86,6 +85,7 @@ docs = [ "sphinxcontrib-towncrier>=0.5.0a0", "sphinxext-opengraph>=0.13", "towncrier>=24.8", + "uv>=0.12.22", ] coverage = [ "covdefaults>=2.3", diff --git a/tox.toml b/tox.toml index 512f9f81..605d5983 100644 --- a/tox.toml +++ b/tox.toml @@ -96,7 +96,11 @@ commands = [ [ "python", "-c", - "import glob; import subprocess; subprocess.check_call(['proselint', 'check'] + glob.glob('docs/*.rst'))", + # RE2 lacks Python 3.15 wheels: https://github.com/google/re2/issues/647 + """\ + import glob; import subprocess; subprocess.check_call(['uv', 'tool', 'run', '--python', '3.14', '--from', \ + 'proselint>=0.16', 'proselint', 'check', *glob.glob('docs/*.rst')])\ + """, ], [ "sphinx-build", From dea3bbdd4211706218baa557cbb64b50416b155b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 9 Oct 2026 17:43:58 -0700 Subject: [PATCH 5/5] docs: remove breaking change classification --- docs/changelog/613.breaking.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/changelog/613.breaking.rst diff --git a/docs/changelog/613.breaking.rst b/docs/changelog/613.breaking.rst deleted file mode 100644 index 56163712..00000000 --- a/docs/changelog/613.breaking.rst +++ /dev/null @@ -1 +0,0 @@ -Require Python 3.11 or newer.