From 4198e17f7c493ef2f777155aab9323bf797f9fd3 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 24 Jul 2026 15:04:29 -0400 Subject: [PATCH 1/5] ci: test Python 3.15 Add 3.15 jobs to the CI matrix on Linux, macOS, and Windows, plus 3.15t on Linux. The upstream workflow, which runs on the 'python dev' label, was still pinned to 3.13; point it at 3.15. Assisted-by: ClaudeCode:claude-opus-5 --- .github/workflows/ci.yml | 12 ++++++++++++ .github/workflows/upstream.yml | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7e9e86429..2ad1178395 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,9 @@ jobs: - runs-on: ubuntu-latest python-version: 'graalpy-25.0' cmake-args: -DCMAKE_CXX_STANDARD=20 + - runs-on: ubuntu-latest + python-version: '3.15' + cmake-args: -DCMAKE_CXX_STANDARD=20 - runs-on: macos-latest python-version: '3.14' cmake-args: -DCMAKE_CXX_STANDARD=14 @@ -86,6 +89,9 @@ jobs: - runs-on: ubuntu-latest python-version: '3.14' cmake-args: -DCMAKE_CXX_STANDARD=14 + - runs-on: ubuntu-latest + python-version: '3.15t' + cmake-args: -DCMAKE_CXX_STANDARD=17 -DPYBIND11_TEST_SMART_HOLDER=ON # No SciPy for macOS ARM - runs-on: macos-15-intel @@ -100,6 +106,9 @@ jobs: - runs-on: macos-latest python-version: '3.14t' cmake-args: -DCMAKE_CXX_STANDARD=20 + - runs-on: macos-latest + python-version: '3.15' + cmake-args: -DCMAKE_CXX_STANDARD=17 - runs-on: macos-latest python-version: 'pypy-3.11-v7.3.23' - runs-on: macos-latest @@ -127,6 +136,9 @@ jobs: - runs-on: windows-latest python-version: '3.14t' cmake-args: -DCMAKE_CXX_STANDARD=23 + - runs-on: windows-latest + python-version: '3.15' + cmake-args: -DCMAKE_CXX_STANDARD=20 - runs-on: windows-latest python-version: 'pypy3.11' cmake-args: -DCMAKE_CXX_STANDARD=20 diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 9639d267c4..d27af5058f 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -18,7 +18,7 @@ env: jobs: standard: - name: "🐍 3.13 latest • ubuntu-latest • x64" + name: "🐍 3.15 latest • ubuntu-latest • x64" runs-on: ubuntu-latest # Only runs when the 'python dev' label is selected if: "contains(github.event.pull_request.labels.*.name, 'python dev')" @@ -26,10 +26,10 @@ jobs: steps: - uses: actions/checkout@v7 - - name: Setup Python 3.13 + - name: Setup Python 3.15 uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.15" allow-prereleases: true - name: Setup Boost From 44d0580ad2bfa6e4326dbd92fd9dff0573fe287e Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 24 Jul 2026 15:07:49 -0400 Subject: [PATCH 2/5] ci: skip numpy on Python 3.15 No released numpy has cp315 wheels, and the install runs under --only-binary, so the 3.15 jobs failed to resolve. Every numpy use in the tests is behind importorskip, so they skip cleanly without it. Assisted-by: ClaudeCode:claude-opus-5 --- tests/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/requirements.txt b/tests/requirements.txt index 53f05b6bb3..1ba4026b46 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,6 +1,8 @@ --extra-index-url=https://www.graalvm.org/python/wheels --only-binary=:all: build>=1 +# No released numpy has cp315 wheels yet; drop the upper bound once it does. +numpy>=2.4.0; platform_python_implementation=="CPython" and python_version>="3.14" and python_version<"3.15" numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy" numpy~=1.25.0; python_version=="3.9" and platform_python_implementation=="PyPy" numpy~=2.2.0; python_version=="3.10" and platform_python_implementation=="PyPy" @@ -10,7 +12,6 @@ numpy~=1.22.2; platform_python_implementation=="CPython" and python_version=="3. numpy~=1.26.0; platform_python_implementation=="CPython" and python_version>="3.11" and python_version<"3.13" and platform_machine!="ARM64" numpy>=2.3.0; platform_python_implementation=="CPython" and python_version>="3.11" and platform_machine=="ARM64" numpy~=2.2.0; platform_python_implementation=="CPython" and python_version=="3.13" and platform_machine!="ARM64" -numpy>=2.4.0; platform_python_implementation=="CPython" and python_version>="3.14" pytest>=6 pytest-timeout scipy~=1.5.4; platform_python_implementation=="CPython" and python_version<"3.10" From 709d01851c7da71b813ec42f5651dc677211a4c4 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 24 Jul 2026 15:17:09 -0400 Subject: [PATCH 3/5] test: strip ANSI codes from captured unraisable traceback Python 3.15 colorizes the traceback the default unraisable hook writes when FORCE_COLOR is set, which CI does, so the endswith check on the exception line failed. Assisted-by: ClaudeCode:claude-opus-5 --- tests/test_exceptions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index e6441f6013..9708a69da5 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re import sys import pytest @@ -123,6 +124,8 @@ def hook(unraisable_hook_args): assert triggered is True _, captured_stderr = capsys.readouterr() + # Python 3.15 colorizes this traceback when FORCE_COLOR is set. + captured_stderr = re.sub(r"\x1b\[[0-9;]*m", "", captured_stderr) assert captured_stderr.startswith("Exception ignored in: 'already_set demo'") assert captured_stderr.rstrip().endswith("KeyError: 'bar'") From 8b8e345a888c5a91e0cab7b26b34ffc7d28bd2f3 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 24 Jul 2026 15:39:11 -0400 Subject: [PATCH 4/5] chore: add Python 3.15 classifier Assisted-by: ClaudeCode:claude-opus-5 --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 03214c6f4b..c3395aa660 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,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 :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: C++", From dfb22b0b6e63e8e6a54ac8dc005614de3d8d068c Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 24 Jul 2026 19:47:22 -0400 Subject: [PATCH 5/5] Update test_exceptions.py Co-authored-by: Ralf W. Grosse-Kunstleve --- tests/test_exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 9708a69da5..1ee13ba3f3 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -124,8 +124,8 @@ def hook(unraisable_hook_args): assert triggered is True _, captured_stderr = capsys.readouterr() - # Python 3.15 colorizes this traceback when FORCE_COLOR is set. - captured_stderr = re.sub(r"\x1b\[[0-9;]*m", "", captured_stderr) + # Strip ANSI codes that Python 3.15+ adds to this traceback under FORCE_COLOR. + captured_stderr = re.sub(r"\x1b\[[0-?]*[ -/]*m", "", captured_stderr) assert captured_stderr.startswith("Exception ignored in: 'already_set demo'") assert captured_stderr.rstrip().endswith("KeyError: 'bar'")