Skip to content

Commit 4bb52eb

Browse files
mdboomleofangclaude
authored
Add Python 3.15 to the test matrix (#2108)
* Add Python 3.15 to the test matrix * Update cibuildwheel * Remove matplotlib dependency * Remove cffi as a test dependency * Use LOCAL_CTK=0 for Python 3.15 * Pre-build numpy for Python 3.15; exclude 3.15 from releases numpy 2.4.x has no pre-built wheel for Python 3.15 yet, and its [tool.cibuildwheel] config is incompatible with cibuildwheel v4.0. Build numpy from patched sdist via cibuildwheel with -Dallow-noblas=true on all platforms (linux-64, linux-aarch64, win-64). Also exclude python315 artifacts from release publishing since 3.15 is pre-release and not ready for PyPI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Drop CIBW_REPAIR_WHEEL_COMMAND_WINDOWS override; version-gate matplotlib/cffi Remove the empty CIBW_REPAIR_WHEEL_COMMAND_WINDOWS that was overriding the pyproject.toml delvewheel config. The pyproject.toml already specifies `delvewheel repair --namespace-pkg cuda` which is the correct behavior. Keep matplotlib and cffi as test dependencies but gate them to python_version < 3.15 (no wheels available yet for 3.15). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Tighten allow-prereleases to Python 3.15 only Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Skip musllinux when building numpy wheel Main's CIBW_BUILD is cp315-* (not cp315-manylinux* like 12.9.x), so cibuildwheel builds both manylinux and musllinux numpy wheels. The musllinux wheel is incompatible with the glibc-based test runners. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix Windows numpy build; allow 3.15 test failures - Skip musllinux and win32 when building numpy (CIBW_BUILD=cp315-* matches both win32 and win_amd64; numpy has no pyproject.toml constraint after we strip its cibuildwheel config) - Mark 3.15/3.15t test jobs as continue-on-error so they don't block CI (3.15t segfaults on CPython beta, rlcompleter test changed behavior) - Skip test_opt_out_env_var_disables_patch_even_when_interactive on Python 3.15 (upstream fixed the rlcompleter bug this test relied on) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Skip nvidia-cutlass on Python 3.15 (scipy unavailable) nvidia-cutlass depends on scipy, which has no pre-built wheel for Python 3.15 yet. Version-gate the dependency so pathfinder tests can still install the rest of the test dependencies on 3.15. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add TODO comments for all Python 3.15 workarounds Mark every temporary 3.15 hack (version-gated deps, numpy pre-build, continue-on-error, allow-prereleases, cpython-prerelease, release exclusion) with a TODO so they are easy to find and remove once 3.15 is officially supported. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Skip cutlass/cute header tests on Python 3.15 nvidia-cutlass is not installed on 3.15 (scipy has no 3.15 wheel), so the pathfinder header discovery tests for cutlass and cute will always fail under all_must_work strictness. Skip those parametrized cases on 3.15+. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix ruff SIM118: use `in dict` instead of `in dict.keys()` Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * disable py315t pipeline for now --------- Co-authored-by: Leo Fang <leof@nvidia.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d83231e commit 4bb52eb

10 files changed

Lines changed: 153 additions & 7 deletions

File tree

.github/workflows/build-wheel.yml

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ jobs:
3434
- "3.13"
3535
- "3.14"
3636
- "3.14t"
37+
- "3.15"
38+
- "3.15t"
3739
name: py${{ matrix.python-version }}
3840
runs-on: ${{ (inputs.host-platform == 'linux-64' && 'linux-amd64-cpu8') ||
3941
(inputs.host-platform == 'linux-aarch64' && 'linux-arm64-cpu8') ||
@@ -165,12 +167,17 @@ jobs:
165167
cuda-version: ${{ inputs.cuda-version }}
166168

167169
- name: Build cuda.bindings wheel
168-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
170+
uses: pypa/cibuildwheel@54327ab9d35de03b359ac25c97de9417d94639c0 # v4.0.0rc1
169171
with:
170172
package-dir: ./cuda_bindings/
171173
output-dir: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}
172174
env:
173175
CIBW_BUILD: ${{ env.CIBW_BUILD }}
176+
# TODO: remove cpython-prerelease once 3.15 is officially supported
177+
# Allow CPython pre-release builds (currently 3.15 / 3.15t). This is a
178+
# no-op for stable Python versions because CIBW_BUILD still filters
179+
# the target version.
180+
CIBW_ENABLE: cpython-prerelease
174181
# CIBW mounts the host filesystem under /host
175182
CIBW_ENVIRONMENT_LINUX: >
176183
CUDA_PATH=/host/${{ env.CUDA_PATH }}
@@ -229,12 +236,17 @@ jobs:
229236
if-no-files-found: error
230237

231238
- name: Build cuda.core wheel
232-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
239+
uses: pypa/cibuildwheel@54327ab9d35de03b359ac25c97de9417d94639c0 # v4.0.0rc1
233240
with:
234241
package-dir: ./cuda_core/
235242
output-dir: ${{ env.CUDA_CORE_ARTIFACTS_DIR }}
236243
env:
237244
CIBW_BUILD: ${{ env.CIBW_BUILD }}
245+
# TODO: remove cpython-prerelease once 3.15 is officially supported
246+
# Allow CPython pre-release builds (currently 3.15 / 3.15t). This is a
247+
# no-op for stable Python versions because CIBW_BUILD still filters
248+
# the target version.
249+
CIBW_ENABLE: cpython-prerelease
238250
# CIBW mounts the host filesystem under /host
239251
CIBW_ENVIRONMENT_LINUX: >
240252
CUDA_PATH=/host/${{ env.CUDA_PATH }}
@@ -330,6 +342,8 @@ jobs:
330342
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
331343
with:
332344
python-version: ${{ matrix.python-version }}
345+
# TODO: remove allow-prereleases once 3.15 is officially supported
346+
allow-prereleases: ${{ startsWith(matrix.python-version, '3.15') }}
333347

334348
- name: verify free-threaded build
335349
if: endsWith(matrix.python-version, 't')
@@ -349,6 +363,71 @@ jobs:
349363
run: |
350364
pip install cuda_pathfinder/*.whl
351365
366+
- name: Hide GNU link.exe so Meson finds MSVC link.exe
367+
if: ${{ startsWith(inputs.host-platform, 'win') }}
368+
run: |
369+
if [ -f "/c/Program Files/Git/usr/bin/link.exe" ]; then
370+
mv "/c/Program Files/Git/usr/bin/link.exe" "/c/Program Files/Git/usr/bin/link.exe.bak"
371+
fi
372+
373+
# TODO: remove the numpy pre-build steps once 3.15 is officially supported
374+
# (numpy will publish pre-built 3.15 wheels at that point)
375+
- name: Download and patch numpy sdist (pre-release Python)
376+
if: ${{ startsWith(matrix.python-version, '3.15') }}
377+
run: |
378+
pip download --no-binary numpy --no-deps "numpy>=1.21.1" -d numpy-sdist/
379+
cd numpy-sdist && tar xf numpy-*.tar.gz && rm numpy-*.tar.gz
380+
# WAR: numpy 2.4.x ships [tool.cibuildwheel] config that is
381+
# incompatible with cibuildwheel v4.0 (cpython-freethreading enable
382+
# group, OpenBLAS before-build scripts, etc.). Strip the cibuildwheel
383+
# sections but preserve [tool.meson-python] (vendored meson path).
384+
python -c "
385+
import glob
386+
for f in glob.glob('numpy-*/pyproject.toml'):
387+
lines, skip = open(f).readlines(), False
388+
out = []
389+
for line in lines:
390+
hdr = line.strip()
391+
if hdr.startswith('[tool.cibuildwheel') or hdr.startswith('[[tool.cibuildwheel'):
392+
skip = True
393+
continue
394+
if skip and hdr.startswith('[') and 'cibuildwheel' not in hdr:
395+
skip = False
396+
if not skip:
397+
out.append(line)
398+
open(f, 'w').writelines(out)
399+
"
400+
echo "NUMPY_SRC_DIR=$(pwd)/$(ls -d numpy-*/)" >> $GITHUB_ENV
401+
402+
- name: Build numpy wheel (pre-release Python)
403+
if: ${{ startsWith(matrix.python-version, '3.15') }}
404+
uses: pypa/cibuildwheel@54327ab9d35de03b359ac25c97de9417d94639c0 # v4.0.0rc1
405+
env:
406+
CIBW_BUILD: ${{ env.CIBW_BUILD }}
407+
CIBW_SKIP: "*-musllinux* *-win32"
408+
CIBW_ARCHS_LINUX: "native"
409+
CIBW_BUILD_VERBOSITY: 1
410+
CIBW_CONFIG_SETTINGS: "setup-args=-Dallow-noblas=true"
411+
CIBW_CONFIG_SETTINGS_WINDOWS: "setup-args=--vsenv setup-args=-Dallow-noblas=true"
412+
CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel"
413+
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair -w {dest_dir} {wheel}"
414+
CIBW_ENABLE: "cpython-prerelease"
415+
with:
416+
package-dir: ${{ env.NUMPY_SRC_DIR }}
417+
output-dir: numpy-wheel/
418+
419+
- name: Upload numpy wheel
420+
if: ${{ startsWith(matrix.python-version, '3.15') }}
421+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
422+
with:
423+
name: numpy-python${{ env.PYTHON_VERSION_FORMATTED }}-${{ inputs.host-platform }}
424+
path: numpy-wheel/*.whl
425+
if-no-files-found: error
426+
427+
- name: Install numpy wheel
428+
if: ${{ startsWith(matrix.python-version, '3.15') }}
429+
run: pip install numpy-wheel/*.whl
430+
352431
- name: Build cuda.bindings Cython tests
353432
run: |
354433
pip install ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}/*.whl --group ./cuda_bindings/pyproject.toml:test
@@ -414,12 +493,17 @@ jobs:
414493
rmdir $OLD_BASENAME
415494
416495
- name: Build cuda.core wheel
417-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
496+
uses: pypa/cibuildwheel@54327ab9d35de03b359ac25c97de9417d94639c0 # v4.0.0rc1
418497
with:
419498
package-dir: ./cuda_core/
420499
output-dir: ${{ env.CUDA_CORE_ARTIFACTS_DIR }}
421500
env:
422501
CIBW_BUILD: ${{ env.CIBW_BUILD }}
502+
# TODO: remove cpython-prerelease once 3.15 is officially supported
503+
# Allow CPython pre-release builds (currently 3.15 / 3.15t). This is a
504+
# no-op for stable Python versions because CIBW_BUILD still filters
505+
# the target version.
506+
CIBW_ENABLE: cpython-prerelease
423507
# CIBW mounts the host filesystem under /host
424508
CIBW_ENVIRONMENT_LINUX: >
425509
CUDA_PATH=/host/${{ env.CUDA_PATH }}

.github/workflows/test-wheel-linux.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ jobs:
102102
fail-fast: false
103103
matrix: ${{ fromJSON(needs.compute-matrix.outputs.MATRIX) }}
104104
runs-on: "${{ matrix.FLAVOR || 'linux' }}-${{ matrix.ARCH }}-gpu-${{ matrix.GPU }}-${{ matrix.DRIVER }}-${{ matrix.GPU_COUNT }}"
105+
# TODO: remove continue-on-error once 3.15 is officially supported
106+
continue-on-error: ${{ startsWith(matrix.PY_VER, '3.15') }}
105107
# The build stage could fail but we want the CI to keep moving.
106108
if: ${{ github.repository_owner == 'nvidia' && !cancelled() }}
107109
# Our self-hosted runners require a container
@@ -258,6 +260,8 @@ jobs:
258260
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
259261
with:
260262
python-version: ${{ matrix.PY_VER }}
263+
# TODO: remove allow-prereleases once 3.15 is officially supported
264+
allow-prereleases: ${{ startsWith(matrix.PY_VER, '3.15') }}
261265
env:
262266
# we use self-hosted runners on which setup-python behaves weirdly (Python include can't be found)...
263267
AGENT_TOOLSDIRECTORY: "/opt/hostedtoolcache"
@@ -270,6 +274,18 @@ jobs:
270274
host-platform: ${{ inputs.host-platform }}
271275
cuda-version: ${{ matrix.CUDA_VER }}
272276

277+
# TODO: remove the numpy wheel steps once 3.15 is officially supported
278+
- name: Download numpy wheel (pre-release Python)
279+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
280+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
281+
with:
282+
name: numpy-python${{ env.PYTHON_VERSION_FORMATTED }}-${{ inputs.host-platform }}
283+
path: numpy-wheel
284+
285+
- name: Install numpy wheel (pre-release Python)
286+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
287+
run: pip install numpy-wheel/*.whl
288+
273289
- name: Set up latest cuda_sanitizer_api
274290
if: ${{ env.SETUP_SANITIZER == '1' }}
275291
uses: ./.github/actions/fetch_ctk

.github/workflows/test-wheel-windows.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ jobs:
9595
fail-fast: false
9696
matrix: ${{ fromJSON(needs.compute-matrix.outputs.MATRIX) }}
9797
if: ${{ github.repository_owner == 'nvidia' && !cancelled() }}
98+
# TODO: remove continue-on-error once 3.15 is officially supported
99+
continue-on-error: ${{ startsWith(matrix.PY_VER, '3.15') }}
98100
runs-on: "windows-${{ matrix.ARCH }}-gpu-${{ matrix.GPU }}-${{ matrix.DRIVER }}-${{ matrix.GPU_COUNT }}"
99101
steps:
100102
- name: Checkout ${{ github.event.repository.name }}
@@ -262,6 +264,19 @@ jobs:
262264
host-platform: ${{ inputs.host-platform }}
263265
cuda-version: ${{ matrix.CUDA_VER }}
264266

267+
# TODO: remove the numpy wheel steps once 3.15 is officially supported
268+
- name: Download numpy wheel (pre-release Python)
269+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
270+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
271+
with:
272+
name: numpy-python${{ env.PYTHON_VERSION_FORMATTED }}-${{ inputs.host-platform }}
273+
path: numpy-wheel
274+
275+
- name: Install numpy wheel (pre-release Python)
276+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
277+
shell: bash --noprofile --norc -xeuo pipefail {0}
278+
run: pip install numpy-wheel/*.whl
279+
265280
- name: Set up test repetition on nightly runs
266281
shell: bash --noprofile --norc -xeuo pipefail {0}
267282
run: echo "PYTEST_ADDOPTS=\"--count=${{ inputs.nruns }}\"" >> "$GITHUB_ENV"

ci/test-matrix.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ linux:
3636
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 't4', GPU_COUNT: '1', DRIVER: 'latest' }
3737
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
3838
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '13.3.0', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
39+
- { ARCH: 'amd64', PY_VER: '3.15', CUDA_VER: '13.3.0', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
40+
# Blocked by NVIDIA/cuda-python#2171
41+
# - { ARCH: 'amd64', PY_VER: '3.15t', CUDA_VER: '13.3.0', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
3942
# linux-aarch64
4043
- { ARCH: 'arm64', PY_VER: '3.10', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
4144
- { ARCH: 'arm64', PY_VER: '3.10', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }

ci/tools/download-wheels

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ do
5656
continue
5757
fi
5858

59+
# TODO: remove the Python 3.15 exclusion once 3.15 is officially supported
60+
# exclude pre-release Python (3.15) wheels from releasing
61+
if [[ "${p}" == *python315* ]]; then
62+
echo "Skipping pre-release Python artifact: $p"
63+
continue
64+
fi
65+
5966
# If we're not downloading "all", only process matching component
6067
if [[ "$COMPONENT" != "all" && "$p" != ${COMPONENT}* ]]; then
6168
continue

cuda_bindings/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ all = [
4646
test = [
4747
"cython>=3.2,<3.3",
4848
"setuptools>=77.0.0",
49-
"matplotlib>=3.5.0", # Required by isoFDModelling_test.py
49+
# TODO: remove the Python 3.15 guard once 3.15 is officially supported
50+
"matplotlib>=3.5.0; python_version < '3.15'",
5051
"numpy>=1.21.1",
5152
"pytest>=6.2.4",
5253
"pytest-benchmark>=3.4.1",

cuda_core/pyproject.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,13 @@ cu12 = ["cuda-bindings[all]==12.*", "cuda-toolkit==12.*"]
5858
cu13 = ["cuda-bindings[all]==13.*", "cuda-toolkit==13.*"]
5959

6060
[dependency-groups]
61-
test = ["cython>=3.2,<3.3", "setuptools", "pytest>=6.2.4", "pytest-benchmark", "pytest-randomly", "pytest-repeat", "pytest-rerunfailures", "pytest-timeout", "cloudpickle", "psutil", "cffi"]
61+
test = [
62+
"cython>=3.2,<3.3", "setuptools", "pytest>=6.2.4", "pytest-benchmark",
63+
"pytest-randomly", "pytest-repeat", "pytest-rerunfailures", "pytest-timeout",
64+
"cloudpickle", "psutil",
65+
# TODO: remove the Python 3.15 guard once 3.15 is officially supported
66+
"cffi; python_version < '3.15'",
67+
]
6268
ml-dtypes = ["ml-dtypes>=0.5.4,<0.6.0"]
6369
test-cu12 = [ {include-group = "ml-dtypes" }, {include-group = "test" }, "cupy-cuda12x; python_version < '3.14'", "cuda-toolkit[cudart]==12.*"] # runtime headers needed by CuPy
6470
test-cu13 = [ {include-group = "ml-dtypes" }, {include-group = "test" }, "cupy-cuda13x; python_version < '3.14'", "cuda-toolkit[cudart]==13.*"] # runtime headers needed by CuPy

cuda_core/tests/test_rlcompleter_patch.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def test_patched_completion_succeeds_on_non_ipc_resource():
9696
assert "allocation_handle: True" in result.stdout, result.stdout
9797

9898

99+
@pytest.mark.skipif(sys.version_info >= (3, 15), reason="Python 3.15 fixed the rlcompleter bug upstream")
99100
def test_opt_out_env_var_disables_patch_even_when_interactive():
100101
"""`CUDA_CORE_DONT_FIX_TAB_COMPLETION=1` must short-circuit before the
101102
interactive check, so the bug reproduces again even under PYTHONINSPECT."""

cuda_pathfinder/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ cu13 = [
4646
"nvidia-nvshmem-cu13; sys_platform != 'win32'",
4747
]
4848
host = [
49-
"nvidia-cutlass",
49+
# TODO: remove the Python 3.15 guard once 3.15 is officially supported
50+
"nvidia-cutlass; python_version < '3.15'",
5051
"nvpl-fft; platform_system == 'Linux' and platform_machine == 'aarch64'",
5152
]
5253

cuda_pathfinder/tests/test_find_nvidia_headers.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import importlib.metadata
1717
import os
1818
import re
19+
import sys
1920
from pathlib import Path
2021

2122
import pytest
@@ -112,7 +113,18 @@ def _fake_cudart_canary_abs_path(ctk_root: Path) -> str:
112113
return str(ctk_root / "lib64" / "libcudart.so.13")
113114

114115

115-
@pytest.mark.parametrize("libname", SUPPORTED_HEADERS_NON_CTK.keys())
116+
# TODO: remove the Python 3.15 guard once 3.15 is officially supported
117+
_CUTLASS_SKIP = pytest.mark.skipif(
118+
sys.version_info >= (3, 15),
119+
reason="nvidia-cutlass not available on Python 3.15 (scipy missing)",
120+
)
121+
_NON_CTK_HEADER_PARAMS = [
122+
pytest.param(name, marks=_CUTLASS_SKIP) if name in ("cutlass", "cute") else name
123+
for name in SUPPORTED_HEADERS_NON_CTK
124+
]
125+
126+
127+
@pytest.mark.parametrize("libname", _NON_CTK_HEADER_PARAMS)
116128
def test_locate_non_ctk_headers(info_summary_append, libname):
117129
hdr_dir = find_nvidia_header_directory(libname)
118130
located_hdr_dir = locate_nvidia_header_directory(libname)

0 commit comments

Comments
 (0)