Skip to content

Commit b9269ad

Browse files
leofangclaude
andauthored
Add Python 3.15 to the build/test matrix (12.9.x backport) (#2133)
* Add Python 3.15 to the build/test matrix Backport of #2108 to the 12.9.x branch so that cuda-bindings 12.9.x wheels are available for Python 3.15, which the main branch needs in order to build cuda-core. - Add 3.15 / 3.15t to the build matrix - Upgrade cibuildwheel to v4.0.0rc1 (required for cpython-prerelease) - Enable cpython-prerelease in CIBW_ENABLE - Add amd64-only test entries for 3.15 / 3.15t (CUDA 12.9.1) * Drop cpython-freethreading from CIBW_ENABLE (default in v4.0) * Drop 3.13t from matrix; fix GNU link.exe on Windows - Remove 3.13t from build matrix and all test matrices (already dropped on main). - Work around Meson finding GNU link.exe (from Git for Windows) instead of MSVC link.exe when building numpy from source for pre-release Python on Windows. * Expand test matrix: arm64 3.15, Windows 3.10-3.15 - Add arm64 entries for 3.15 / 3.15t (linux pull-request) - Add Windows pull-request entries for 3.10, 3.11, 3.14, 3.14t, 3.15, 3.15t to keep in sync with main * Windows test matrix: dual LOCAL_CTK for 3.10/3.11, use 12.9.1 for 3.13 * Pre-build numpy wheel for Python 3.15 (no pre-built wheel yet) NumPy does not ship pre-built wheels for Python 3.15 yet. Build the wheel from source during the build stage (where compilers are available), upload it as an artifact, and download/install it in the test stage before running cuda.bindings tests. * Build numpy in manylinux container for glibc compat; fix Windows glob Linux: build numpy via cibuildwheel inside the manylinux_2_28 container so the wheel is compatible with the ubuntu:22.04 test container (glibc 2.35). Previously, pip wheel on the host produced a linux_x86_64 wheel linked against glibc 2.38+, causing ImportError at test time. Windows: add explicit bash shell to the numpy install step in the test workflow — PowerShell does not expand *.whl globs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix numpy cibuildwheel: patch cpython-freethreading, unify platforms - Patch numpy 2.4.x pyproject.toml to remove the "cpython-freethreading" enable group, which is invalid in cibuildwheel v4.0 (fixed on numpy main but not yet released). - Consolidate Linux/Windows numpy builds into a single cibuildwheel step, matching how cuda.core and cuda.bindings are built. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Strip numpy cibuildwheel config; build without BLAS numpy 2.4.x ships [tool.cibuildwheel] config (OpenBLAS scripts, cpython-freethreading, ILP64 settings) incompatible with cibuildwheel v4.0. Strip the entire section from the sdist and build with -Dallow-noblas=true — we only need numpy for testing, not optimized linear algebra. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix numpy pyproject.toml patch to preserve [tool.meson-python] The previous regex stripped everything from [tool.cibuildwheel] to EOF, which also removed [tool.meson-python] with its vendored meson path. Use a line-by-line approach to only remove cibuildwheel sections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix test_graphics_api_smoketest on py3.10/3.11 Windows On py3.10/3.11, pyglet raises FileNotFoundError (an OSError subclass) when opengl32.dll is missing, rather than AttributeError as on py3.12+. Add OSError to the except clause so the test skips gracefully. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Exclude Python 3.15 wheels from release publishing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a4e89b5 commit b9269ad

7 files changed

Lines changed: 120 additions & 18 deletions

File tree

.github/workflows/build-wheel.yml

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ jobs:
2929
- "3.11"
3030
- "3.12"
3131
- "3.13"
32-
- "3.13t"
3332
- "3.14"
3433
- "3.14t"
34+
- "3.15"
35+
- "3.15t"
3536
name: py${{ matrix.python-version }}
3637
runs-on: ${{ (inputs.host-platform == 'linux-64' && 'linux-amd64-cpu8') ||
3738
(inputs.host-platform == 'linux-aarch64' && 'linux-arm64-cpu8') ||
@@ -111,7 +112,7 @@ jobs:
111112
if-no-files-found: error
112113

113114
- name: Build cuda.core wheel
114-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
115+
uses: pypa/cibuildwheel@54327ab9d35de03b359ac25c97de9417d94639c0 # v4.0.0rc1
115116
env:
116117
CIBW_BUILD: ${{ env.CIBW_BUILD }}
117118
CIBW_ARCHS_LINUX: "native"
@@ -120,7 +121,7 @@ jobs:
120121
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --namespace-pkg cuda -w {dest_dir} {wheel}"
121122
CIBW_ENVIRONMENT: >
122123
CUDA_PYTHON_PARALLEL_LEVEL=${{ env.CUDA_PYTHON_PARALLEL_LEVEL }}
123-
CIBW_ENABLE: "cpython-freethreading"
124+
CIBW_ENABLE: "cpython-prerelease"
124125
with:
125126
package-dir: ./cuda_core/
126127
output-dir: ${{ env.CUDA_CORE_ARTIFACTS_DIR }}
@@ -154,7 +155,7 @@ jobs:
154155
cuda-version: ${{ inputs.cuda-version }}
155156

156157
- name: Build cuda.bindings wheel
157-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
158+
uses: pypa/cibuildwheel@54327ab9d35de03b359ac25c97de9417d94639c0 # v4.0.0rc1
158159
env:
159160
CIBW_BUILD: ${{ env.CIBW_BUILD }}
160161
CIBW_ARCHS_LINUX: "native"
@@ -168,7 +169,7 @@ jobs:
168169
CUDA_PYTHON_PARALLEL_LEVEL=${{ env.CUDA_PYTHON_PARALLEL_LEVEL }}
169170
CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel"
170171
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --namespace-pkg cuda -w {dest_dir} {wheel}"
171-
CIBW_ENABLE: "cpython-freethreading"
172+
CIBW_ENABLE: "cpython-prerelease"
172173
with:
173174
package-dir: ./cuda_bindings/
174175
output-dir: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}
@@ -249,6 +250,68 @@ jobs:
249250
run: |
250251
pip install cuda_pathfinder/*.whl
251252
253+
- name: Hide GNU link.exe so Meson finds MSVC link.exe
254+
if: ${{ startsWith(inputs.host-platform, 'win') }}
255+
run: |
256+
if [ -f "/c/Program Files/Git/usr/bin/link.exe" ]; then
257+
mv "/c/Program Files/Git/usr/bin/link.exe" "/c/Program Files/Git/usr/bin/link.exe.bak"
258+
fi
259+
260+
- name: Download and patch numpy sdist (pre-release Python)
261+
if: ${{ startsWith(matrix.python-version, '3.15') }}
262+
run: |
263+
pip download --no-binary numpy --no-deps "numpy>=1.21.1" -d numpy-sdist/
264+
cd numpy-sdist && tar xf numpy-*.tar.gz && rm numpy-*.tar.gz
265+
# WAR: numpy 2.4.x ships [tool.cibuildwheel] config that is
266+
# incompatible with cibuildwheel v4.0 (cpython-freethreading enable
267+
# group, OpenBLAS before-build scripts, etc.). Strip the cibuildwheel
268+
# sections but preserve [tool.meson-python] (vendored meson path).
269+
python -c "
270+
import glob
271+
for f in glob.glob('numpy-*/pyproject.toml'):
272+
lines, skip = open(f).readlines(), False
273+
out = []
274+
for line in lines:
275+
hdr = line.strip()
276+
if hdr.startswith('[tool.cibuildwheel') or hdr.startswith('[[tool.cibuildwheel'):
277+
skip = True
278+
continue
279+
if skip and hdr.startswith('[') and 'cibuildwheel' not in hdr:
280+
skip = False
281+
if not skip:
282+
out.append(line)
283+
open(f, 'w').writelines(out)
284+
"
285+
echo "NUMPY_SRC_DIR=$(pwd)/$(ls -d numpy-*/)" >> $GITHUB_ENV
286+
287+
- name: Build numpy wheel (pre-release Python)
288+
if: ${{ startsWith(matrix.python-version, '3.15') }}
289+
uses: pypa/cibuildwheel@54327ab9d35de03b359ac25c97de9417d94639c0 # v4.0.0rc1
290+
env:
291+
CIBW_BUILD: ${{ env.CIBW_BUILD }}
292+
CIBW_ARCHS_LINUX: "native"
293+
CIBW_BUILD_VERBOSITY: 1
294+
CIBW_CONFIG_SETTINGS: "setup-args=-Dallow-noblas=true"
295+
CIBW_CONFIG_SETTINGS_WINDOWS: "setup-args=--vsenv setup-args=-Dallow-noblas=true"
296+
CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel"
297+
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair -w {dest_dir} {wheel}"
298+
CIBW_ENABLE: "cpython-prerelease"
299+
with:
300+
package-dir: ${{ env.NUMPY_SRC_DIR }}
301+
output-dir: numpy-wheel/
302+
303+
- name: Upload numpy wheel
304+
if: ${{ startsWith(matrix.python-version, '3.15') }}
305+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
306+
with:
307+
name: numpy-python${{ env.PYTHON_VERSION_FORMATTED }}-${{ inputs.host-platform }}
308+
path: numpy-wheel/*.whl
309+
if-no-files-found: error
310+
311+
- name: Install numpy wheel
312+
if: ${{ startsWith(matrix.python-version, '3.15') }}
313+
run: pip install numpy-wheel/*.whl
314+
252315
- name: Build cuda.bindings Cython tests
253316
run: |
254317
pip install $(ls ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}/*.whl)[test]

.github/workflows/release.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ jobs:
163163
if [[ "${p}" == *-tests ]]; then
164164
continue
165165
fi
166+
# exclude pre-release Python (3.15) wheels from publishing
167+
if [[ "${p}" == *python315* ]]; then
168+
continue
169+
fi
166170
mv ${p}/*.whl dist/
167171
done
168172
rm -rf ${{ inputs.component }}*

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,17 @@ jobs:
240240
- name: Set up compute-sanitizer
241241
run: setup-sanitizer
242242

243+
- name: Download numpy wheel (pre-release Python)
244+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
245+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
246+
with:
247+
name: numpy-python${{ env.PYTHON_VERSION_FORMATTED }}-${{ inputs.host-platform }}
248+
path: numpy-wheel
249+
250+
- name: Install numpy wheel (pre-release Python)
251+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
252+
run: pip install numpy-wheel/*.whl
253+
243254
- name: Run cuda.bindings tests
244255
if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0' }}
245256
env:

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,18 @@ jobs:
215215
host-platform: ${{ inputs.host-platform }}
216216
cuda-version: ${{ matrix.CUDA_VER }}
217217

218+
- name: Download numpy wheel (pre-release Python)
219+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
220+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
221+
with:
222+
name: numpy-python${{ env.PYTHON_VERSION_FORMATTED }}-${{ inputs.host-platform }}
223+
path: numpy-wheel
224+
225+
- name: Install numpy wheel (pre-release Python)
226+
if: ${{ startsWith(matrix.PY_VER, '3.15') }}
227+
shell: bash --noprofile --norc -xeuo pipefail {0}
228+
run: pip install numpy-wheel/*.whl
229+
218230
- name: Run cuda.bindings tests
219231
if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0' }}
220232
env:

ci/test-matrix.json

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "13.0.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
1313
{ "ARCH": "amd64", "PY_VER": "3.13", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
1414
{ "ARCH": "amd64", "PY_VER": "3.13", "CUDA_VER": "13.0.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
15-
{ "ARCH": "amd64", "PY_VER": "3.13t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
1615
{ "ARCH": "amd64", "PY_VER": "3.14", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
1716
{ "ARCH": "amd64", "PY_VER": "3.14t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
17+
{ "ARCH": "amd64", "PY_VER": "3.15", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
18+
{ "ARCH": "amd64", "PY_VER": "3.15t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
1819
{ "ARCH": "arm64", "PY_VER": "3.10", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "a100", "DRIVER": "latest" },
1920
{ "ARCH": "arm64", "PY_VER": "3.10", "CUDA_VER": "13.0.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" },
2021
{ "ARCH": "arm64", "PY_VER": "3.11", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" },
@@ -23,9 +24,10 @@
2324
{ "ARCH": "arm64", "PY_VER": "3.12", "CUDA_VER": "13.0.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" },
2425
{ "ARCH": "arm64", "PY_VER": "3.13", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" },
2526
{ "ARCH": "arm64", "PY_VER": "3.13", "CUDA_VER": "13.0.1", "LOCAL_CTK": "1", "GPU": "a100", "DRIVER": "latest" },
26-
{ "ARCH": "arm64", "PY_VER": "3.13t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "a100", "DRIVER": "latest" },
2727
{ "ARCH": "arm64", "PY_VER": "3.14", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "a100", "DRIVER": "latest" },
28-
{ "ARCH": "arm64", "PY_VER": "3.14t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" }
28+
{ "ARCH": "arm64", "PY_VER": "3.14t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" },
29+
{ "ARCH": "arm64", "PY_VER": "3.15", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" },
30+
{ "ARCH": "arm64", "PY_VER": "3.15t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "a100", "DRIVER": "latest" }
2931
],
3032
"nightly": [
3133
{ "ARCH": "amd64", "PY_VER": "3.10", "CUDA_VER": "11.8.0", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "earliest" },
@@ -77,20 +79,24 @@
7779
},
7880
"windows": {
7981
"pull-request": [
80-
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
81-
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "t4", "DRIVER": "latest" },
82-
{ "ARCH": "amd64", "PY_VER": "3.13", "CUDA_VER": "13.0.1", "LOCAL_CTK": "0", "GPU": "t4", "DRIVER": "latest" },
83-
{ "ARCH": "amd64", "PY_VER": "3.13", "CUDA_VER": "13.0.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
84-
{ "ARCH": "amd64", "PY_VER": "3.13t", "CUDA_VER": "13.0.1", "LOCAL_CTK": "0", "GPU": "t4", "DRIVER": "latest" },
85-
{ "ARCH": "amd64", "PY_VER": "3.13t", "CUDA_VER": "13.0.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" }
82+
{ "ARCH": "amd64", "PY_VER": "3.10", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
83+
{ "ARCH": "amd64", "PY_VER": "3.10", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "t4", "DRIVER": "latest" },
84+
{ "ARCH": "amd64", "PY_VER": "3.11", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "t4", "DRIVER": "latest" },
85+
{ "ARCH": "amd64", "PY_VER": "3.11", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
86+
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
87+
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "t4", "DRIVER": "latest" },
88+
{ "ARCH": "amd64", "PY_VER": "3.13", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "t4", "DRIVER": "latest" },
89+
{ "ARCH": "amd64", "PY_VER": "3.13", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
90+
{ "ARCH": "amd64", "PY_VER": "3.14", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "t4", "DRIVER": "latest" },
91+
{ "ARCH": "amd64", "PY_VER": "3.14t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
92+
{ "ARCH": "amd64", "PY_VER": "3.15", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
93+
{ "ARCH": "amd64", "PY_VER": "3.15t", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" }
8694
],
8795
"nightly": [
8896
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "11.8.0", "LOCAL_CTK": "0", "GPU": "l4", "DRIVER": "latest" },
8997
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "11.8.0", "LOCAL_CTK": "1", "GPU": "t4", "DRIVER": "latest" },
9098
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "12.9.1", "LOCAL_CTK": "0", "GPU": "t4", "DRIVER": "latest" },
91-
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" },
92-
{ "ARCH": "amd64", "PY_VER": "3.13t", "CUDA_VER": "13.0.1", "LOCAL_CTK": "0", "GPU": "t4", "DRIVER": "latest" },
93-
{ "ARCH": "amd64", "PY_VER": "3.13t", "CUDA_VER": "13.0.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" }
99+
{ "ARCH": "amd64", "PY_VER": "3.12", "CUDA_VER": "12.9.1", "LOCAL_CTK": "1", "GPU": "l4", "DRIVER": "latest" }
94100
]
95101
}
96102
}

ci/tools/download-wheels

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

59+
# exclude pre-release Python (3.15) wheels from releasing
60+
if [[ "${p}" == *python315* ]]; then
61+
echo "Skipping pre-release Python artifact: $p"
62+
continue
63+
fi
64+
5965
# If we're not downloading "all", only process matching component
6066
if [[ "$COMPONENT" != "all" && "$p" != ${COMPONENT}* ]]; then
6167
continue

cuda_bindings/tests/test_graphics_apis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_graphics_api_smoketest():
1212
import pyglet
1313

1414
tex = pyglet.image.Texture.create(512, 512)
15-
except (ImportError, AttributeError):
15+
except (ImportError, AttributeError, OSError):
1616
pytest.skip("pyglet not available or could not create GL context")
1717
# return to make linters happy
1818
return

0 commit comments

Comments
 (0)