From 09635f613701da493c723167ef8704e728cea67f Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 20 Oct 2026 21:40:08 -0700 Subject: [PATCH 01/19] Test and document both bindings lines from main Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/actions/doc_preview/action.yml | 2 +- .github/workflows/build-docs.yml | 132 ++++--- .github/workflows/ci-nightly.yml | 62 ++-- .github/workflows/ci-pixi-source-test.yml | 268 +++++++++++--- .github/workflows/coverage.yml | 56 ++- .github/workflows/test-wheel-linux.yml | 200 ++++++----- .github/workflows/test-wheel-windows.yml | 194 ++++++---- ci/tools/run-tests | 72 +++- .../test_pixi_lockfile_freshness_workflow.py | 12 +- ci/tools/tests/test_test_sources.py | 340 ++++++++++++++++++ cuda_bindings_13/docs/build_docs.sh | 9 +- cuda_bindings_13/docs/source/install.rst | 6 +- cuda_python/docs/environment-docs.yml | 2 + toolshed/setup-docs-env.sh | 1 + 14 files changed, 1029 insertions(+), 327 deletions(-) create mode 100644 ci/tools/tests/test_test_sources.py diff --git a/.github/actions/doc_preview/action.yml b/.github/actions/doc_preview/action.yml index a0c7f212297..3a4373b3a63 100644 --- a/.github/actions/doc_preview/action.yml +++ b/.github/actions/doc_preview/action.yml @@ -20,7 +20,7 @@ runs: steps: - name: Deploy doc preview if: ${{ startsWith(github.ref_name, 'pull-request/') }} - uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0 + uses: JamesIves/github-pages-deploy-action@fa24774553152dd7873cd16ebd8d959b010c5445 # v4.9.0 with: git-config-name: cuda-python-bot git-config-email: cuda-python-bot@users.noreply.github.com diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index b1c029f62cf..d121389e57c 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -43,6 +43,11 @@ on: required: false default: "gh-pages" type: string + bindings-package: + description: "Resolved CUDA bindings package JSON" + required: false + default: "" + type: string jobs: build: @@ -62,23 +67,39 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 1 - ref: ${{ inputs.git-tag }} + ref: ${{ inputs.is-release && format('refs/tags/{0}', inputs.git-tag) || inputs.git-tag }} + + # Release sources and workflow tools can come from different commits. + # Keep the shared CI helpers at this workflow revision while reading + # package paths and toolkit settings from the checked-out release tag. + - name: Checkout docs control plane + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + path: .ci-control - - name: Read build CTK version + - name: Install CI tool dependencies + run: python3 -m pip install -e ./.ci-control/ci + + - name: Resolve CUDA bindings package + env: + BINDINGS_PACKAGE: ${{ inputs.bindings-package }} + IS_RELEASE: ${{ inputs.is-release }} + RELEASE_TAG: ${{ inputs.git-tag }} run: | - if [[ -f ci/versions.yml ]]; then - BUILD_CTK_VER=$(yq '.cuda.build.version' ci/versions.yml) - elif [[ -f ci/versions.json ]]; then - BUILD_CTK_VER=$(jq -r '.cuda.build.version' ci/versions.json) + set -euo pipefail + if [[ -n "$BINDINGS_PACKAGE" ]]; then + resolved_bindings_package="$BINDINGS_PACKAGE" + elif [[ "${IS_RELEASE}" == "true" ]]; then + resolved_bindings_package=$(cd .ci-control && python3 -m ci.tools.bindings_config \ + --release-tag "$RELEASE_TAG" \ + --release-source-root ..) else - echo "error: cannot find ci/versions.yml or ci/versions.json" >&2 - exit 1 - fi - if [[ ! "${BUILD_CTK_VER}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "error: derived CTK build version ${BUILD_CTK_VER} does not match MAJOR.MINOR.MICRO" >&2 - exit 1 + resolved_bindings_package=$(cd .ci-control && python3 -m ci.tools.bindings_config \ + --release-status current) fi - echo "BUILD_CTK_VER=${BUILD_CTK_VER}" >> "$GITHUB_ENV" + (cd .ci-control && python3 -m ci.tools.bindings_config \ + write-github-env "$GITHUB_ENV" <<< "$resolved_bindings_package") # TODO: This workflow runs on GH-hosted runner and cannot use the proxy cache @@ -86,7 +107,7 @@ jobs: uses: conda-incubator/setup-miniconda@be893c923ea9cf1cf7cd510fbdde27c7e18cbdcb # v4.1.0 with: activate-environment: cuda-python-docs - environment-file: ./cuda_python/docs/environment-docs.yml + environment-file: ./.ci-control/cuda_python/docs/environment-docs.yml miniforge-version: latest conda-remove-defaults: "true" python-version: 3.12 @@ -106,24 +127,16 @@ jobs: cuda-version: ${{ env.BUILD_CTK_VER }} - name: Set environment variables + env: + IS_RELEASE: ${{ inputs.is-release }} + RELEASE_TAG: ${{ inputs.git-tag }} run: | PYTHON_VERSION_FORMATTED="312" # see above REPO_DIR=$(pwd) - # Release docs may check out tags from before the source-root rename. - if [[ -d cuda_bindings_13 ]]; then - CUDA_BINDINGS_SOURCE_DIR=cuda_bindings_13 - elif [[ -d cuda_bindings ]]; then - CUDA_BINDINGS_SOURCE_DIR=cuda_bindings - else - echo "error: cannot find the cuda.bindings source directory" >&2 - exit 1 - fi - echo "CUDA_BINDINGS_SOURCE_DIR=${CUDA_BINDINGS_SOURCE_DIR}" >> "$GITHUB_ENV" - - if [[ ${{ inputs.is-release }} == "true" ]]; then + if [[ "$IS_RELEASE" == "true" ]]; then FILE_HASH="*" - DOCS_GITHUB_REF="${{ inputs.git-tag }}" + DOCS_GITHUB_REF="$RELEASE_TAG" if [[ -z "${DOCS_GITHUB_REF}" ]]; then DOCS_GITHUB_REF="${GITHUB_REF_NAME}" fi @@ -132,6 +145,8 @@ jobs: DOCS_GITHUB_REF=$(python ci/tools/checkout_source_links.py --github-ref) fi + echo "CUDA_BINDINGS_SOURCE_DIR=${BINDINGS_PACKAGE_ROOT}" >> "$GITHUB_ENV" + # make outputs from the previous job as env vars CUDA_CORE_ARTIFACT_BASENAME="cuda-core-python${PYTHON_VERSION_FORMATTED}-linux-64" echo "CUDA_PYTHON_DOCS_GITHUB_REF=${DOCS_GITHUB_REF}" >> $GITHUB_ENV @@ -141,22 +156,27 @@ jobs: CUDA_BINDINGS_ARTIFACT_BASENAME="cuda-bindings-python${PYTHON_VERSION_FORMATTED}-cuda${BUILD_CTK_VER}-linux-64" echo "CUDA_BINDINGS_ARTIFACT_BASENAME=${CUDA_BINDINGS_ARTIFACT_BASENAME}" >> $GITHUB_ENV echo "CUDA_BINDINGS_ARTIFACT_NAME=${CUDA_BINDINGS_ARTIFACT_BASENAME}-${FILE_HASH}" >> $GITHUB_ENV - echo "CUDA_BINDINGS_ARTIFACTS_DIR=$(realpath "$REPO_DIR/$CUDA_BINDINGS_SOURCE_DIR/dist")" >> $GITHUB_ENV + echo "CUDA_BINDINGS_ARTIFACTS_DIR=$(realpath "$REPO_DIR/${BINDINGS_PACKAGE_ROOT}/dist")" >> $GITHUB_ENV + CUDA_PYTHON_ARTIFACT_NAME="cuda-python-wheel-cuda${BUILD_CTK_VER}" + echo "CUDA_PYTHON_ARTIFACT_NAME=${CUDA_PYTHON_ARTIFACT_NAME}" >> $GITHUB_ENV - name: Download cuda-python build artifacts + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-python' }} uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: - name: cuda-python-wheel + name: ${{ env.CUDA_PYTHON_ARTIFACT_NAME }} path: . run-id: ${{ inputs.run-id }} github-token: ${{ github.token }} - name: Display structure of downloaded cuda-python artifacts + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-python' }} run: | pwd ls -lahR . - name: Download cuda-pathfinder build artifacts + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-pathfinder' || inputs.component == 'cuda-core' }} uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: cuda-pathfinder-wheel @@ -165,6 +185,7 @@ jobs: github-token: ${{ github.token }} - name: Display structure of downloaded cuda-pathfinder artifacts + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-pathfinder' || inputs.component == 'cuda-core' }} run: | pwd ls -lahR cuda_pathfinder @@ -177,7 +198,7 @@ jobs: path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }} - name: Download cuda.bindings build artifacts - if: ${{ inputs.is-release }} + if: ${{ inputs.is-release && (inputs.component == 'all' || inputs.component == 'cuda-bindings' || inputs.component == 'cuda-core') }} uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: pattern: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} @@ -187,6 +208,7 @@ jobs: github-token: ${{ github.token }} - name: Display structure of downloaded cuda.bindings artifacts + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-bindings' || inputs.component == 'cuda-core' }} run: | pwd ls -lahR $CUDA_BINDINGS_ARTIFACTS_DIR @@ -199,7 +221,7 @@ jobs: path: ${{ env.CUDA_CORE_ARTIFACTS_DIR }} - name: Download cuda.core build artifacts - if: ${{ inputs.is-release }} + if: ${{ inputs.is-release && (inputs.component == 'all' || inputs.component == 'cuda-core') }} uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: pattern: ${{ env.CUDA_CORE_ARTIFACT_NAME }} @@ -209,26 +231,37 @@ jobs: github-token: ${{ github.token }} - name: Display structure of downloaded cuda.core build artifacts + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-core' }} run: | pwd ls -lahR $CUDA_CORE_ARTIFACTS_DIR - - name: Install all packages + - name: Install cuda-pathfinder + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-pathfinder' || inputs.component == 'cuda-core' }} run: | pushd cuda_pathfinder pip install *.whl popd + - name: Install cuda.bindings + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-bindings' || inputs.component == 'cuda-core' }} + run: | pushd "${CUDA_BINDINGS_ARTIFACTS_DIR}" pip install *.whl popd + - name: Install cuda.core + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-core' }} + run: | pushd "${CUDA_CORE_ARTIFACTS_DIR}" pip install *.whl popd - # Subpackages are already installed from CI artifacts above. - # --no-deps avoids re-resolving cuda-core from PyPI during tag releases. + - name: Install cuda-python + if: ${{ !inputs.is-release || inputs.component == 'all' || inputs.component == 'cuda-python' }} + run: | + # Documentation builds do not exercise runtime dependencies. + # --no-deps also avoids resolving artifacts absent from focused tag runs. pip install --no-deps cuda_python*.whl # PR CI uses pull-request/ refs regardless of the target branch. @@ -252,9 +285,11 @@ jobs: - name: Build all docs if: ${{ inputs.component == 'all' }} + env: + IS_RELEASE: ${{ inputs.is-release }} run: | pushd cuda_python/docs/ - if [[ "${{ inputs.is-release }}" == "false" ]]; then + if [[ "$IS_RELEASE" == "false" ]]; then ./build_all_docs.sh latest-only else ./build_all_docs.sh @@ -271,13 +306,20 @@ jobs: - name: Build component docs if: ${{ inputs.component != 'all' }} + env: + DOCS_COMPONENT: ${{ inputs.component }} + IS_RELEASE: ${{ inputs.is-release }} run: | - COMPONENT=$(echo "${{ inputs.component }}" | tr '-' '_') - if [[ "${{ inputs.component }}" == "cuda-bindings" ]]; then - COMPONENT="${CUDA_BINDINGS_SOURCE_DIR}" + case "$DOCS_COMPONENT" in + cuda-bindings|cuda-core|cuda-pathfinder|cuda-python) ;; + *) echo "error: unsupported docs component: $DOCS_COMPONENT" >&2; exit 1 ;; + esac + COMPONENT="${DOCS_COMPONENT//-/_}" + if [[ "$DOCS_COMPONENT" == "cuda-bindings" ]]; then + COMPONENT="${BINDINGS_PACKAGE_ROOT}" fi - pushd ${COMPONENT}/docs/ - if [[ "${{ inputs.is-release }}" == "false" ]]; then + pushd "${COMPONENT}/docs/" + if [[ "$IS_RELEASE" == "false" ]]; then ./build_docs.sh latest-only else ./build_docs.sh @@ -290,13 +332,13 @@ jobs: fi ls -l build popd - if [[ "${{ inputs.component }}" != "cuda-python" ]]; then - TARGET="${{ inputs.component }}" - mkdir -p artifacts/docs/${TARGET} + if [[ "$DOCS_COMPONENT" != "cuda-python" ]]; then + TARGET="$DOCS_COMPONENT" + mkdir -p "artifacts/docs/${TARGET}" else TARGET="" fi - mv ${COMPONENT}/docs/build/html/* artifacts/docs/${TARGET} + mv "${COMPONENT}"/docs/build/html/* "artifacts/docs/${TARGET}" # Check links and anchors in the rendered HTML built above. # Links in authored Markdown and reST files are checked separately by the @@ -363,7 +405,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 1 - ref: ${{ inputs.git-tag }} + ref: ${{ inputs.is-release && format('refs/tags/{0}', inputs.git-tag) || inputs.git-tag }} - name: Download docs deployment payload uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index 0abfdd626cb..072758c561b 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -65,7 +65,7 @@ jobs: - name: Run CI tools unit tests run: | - python -m pip install pytest pyyaml==6.0.3 + python -m pip install -e './ci[test]' # Standalone CI tool tests; skip repo-root conftest.py (imports cuda.pathfinder). python -m pytest -v --noconftest ci/tools/tests @@ -75,26 +75,36 @@ jobs: outputs: RUN_ID: ${{ steps.find.outputs.run_id }} HEAD_SHA: ${{ steps.find.outputs.head_sha }} - CUDA_BUILD_VER: ${{ steps.find.outputs.cuda_build_ver }} + BINDINGS_CONFIG: ${{ steps.find.outputs.bindings_config }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 1 + - name: Install CI tool dependencies + run: python -m pip install -e ./ci + - name: Find latest successful CI run on main id: find env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_REPOSITORY: ${{ github.repository }} + REQUESTED_RUN_ID: ${{ inputs.run-id }} run: | - if [[ -n "${{ inputs.run-id }}" ]]; then - RUN_ID="${{ inputs.run-id }}" + set -euo pipefail + if [[ -n "$REQUESTED_RUN_ID" ]]; then + if [[ ! "$REQUESTED_RUN_ID" =~ ^[1-9][0-9]*$ ]]; then + echo "::error::run-id must be a positive integer" + exit 1 + fi + RUN_ID="$REQUESTED_RUN_ID" HEAD_SHA=$(gh run view "$RUN_ID" \ - -R "${{ github.repository }}" \ + -R "$RELEASE_REPOSITORY" \ --json headSha | jq -r '.headSha') else # lookup-run-id --branch --head-sha prints two lines: run_id then head_sha - OUTPUT=$(./ci/tools/lookup-run-id --branch main --head-sha "${{ github.repository }}" "CI") + OUTPUT=$(./ci/tools/lookup-run-id --branch main --head-sha "$RELEASE_REPOSITORY" "CI") RUN_ID=$(echo "$OUTPUT" | sed -n '1p') HEAD_SHA=$(echo "$OUTPUT" | sed -n '2p') fi @@ -104,20 +114,16 @@ jobs: exit 1 fi - CUDA_BUILD_VER=$(gh api \ - "repos/${{ github.repository }}/contents/ci/versions.yml?ref=$HEAD_SHA" \ - --jq '.content' \ - | base64 -d \ - | yq '.cuda.build.version') - - if [[ -z "$CUDA_BUILD_VER" || "$CUDA_BUILD_VER" == "null" ]]; then - echo "::error::Could not resolve CUDA build version from $HEAD_SHA" - exit 1 - fi + git fetch --depth=1 origin "$HEAD_SHA" + snapshot=$(mktemp -d) + trap 'rm -rf -- "$snapshot"' EXIT + git archive "$HEAD_SHA" | tar -x -C "$snapshot" + BINDINGS_CONFIG=$(python -m ci.tools.bindings_config \ + --config "$snapshot/ci/versions.yml") echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT echo "head_sha=$HEAD_SHA" >> $GITHUB_OUTPUT - echo "cuda_build_ver=$CUDA_BUILD_VER" >> $GITHUB_OUTPUT + echo "bindings_config=$BINDINGS_CONFIG" >> $GITHUB_OUTPUT # ── PyTorch interop tests ── @@ -133,7 +139,7 @@ jobs: with: build-type: nightly host-platform: linux-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-pytorch @@ -151,7 +157,7 @@ jobs: with: build-type: nightly host-platform: linux-aarch64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-pytorch @@ -169,7 +175,7 @@ jobs: with: build-type: nightly host-platform: win-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-pytorch @@ -189,7 +195,7 @@ jobs: with: build-type: nightly host-platform: linux-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-numba-cuda @@ -207,7 +213,7 @@ jobs: with: build-type: nightly host-platform: linux-aarch64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-numba-cuda @@ -225,7 +231,7 @@ jobs: with: build-type: nightly host-platform: win-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-numba-cuda @@ -245,7 +251,7 @@ jobs: with: build-type: nightly host-platform: linux-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-numba-cuda-mlir @@ -263,7 +269,7 @@ jobs: with: build-type: nightly host-platform: win-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-numba-cuda-mlir @@ -283,7 +289,7 @@ jobs: with: build-type: nightly host-platform: linux-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-cuda-core @@ -301,7 +307,7 @@ jobs: with: build-type: nightly host-platform: win-64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: nightly-cuda-core @@ -321,7 +327,7 @@ jobs: with: build-type: nightly host-platform: linux-aarch64 - build-ctk-ver: ${{ needs.find-wheels.outputs.CUDA_BUILD_VER }} + bindings-config: ${{ needs.find-wheels.outputs.BINDINGS_CONFIG }} run-id: ${{ needs.find-wheels.outputs.RUN_ID }} sha: ${{ needs.find-wheels.outputs.HEAD_SHA }} test-mode: standard diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index a09f2e2756f..a6456f72d33 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -11,14 +11,14 @@ # cython-test build mechanics drift (see #2182, #2183). This workflow is the # only thing that runs the pixi source build end to end. # -# Two tiers, to spend GPU minutes deliberately (GPUs are scarce): +# Three tiers, to spend GPU minutes deliberately (GPUs are scarce): # - build-smoke (PRs): CPU-only. Source-builds bindings + core, imports them, # builds the cython test extensions and checks placement. Catches the # compile / ABI / .so-placement regressions WITHOUT a GPU. -# - build-identity-roundtrip (nightly + manual): CPU-only. cu13 -> cu12 -> -# cu13 in one checkout, so build artifacts cannot be reused across CUDA -# majors. Kept off PRs to avoid adding another job to the org's shared -# concurrent-job quota; the fast unit tests in +# - build-identity-roundtrip (nightly + manual): CPU-only. The current ABI -> +# another configured ABI -> current ABI in one checkout, so build artifacts +# cannot be reused across CUDA majors. Kept off PRs to avoid adding another +# job to the org's shared concurrent-job quota; the fast unit tests in # cuda_core/tests/test_build_hooks.py cover the same intent per-PR. # - full-test (nightly + manual): GPU runner, full `pixi run test`. @@ -41,11 +41,15 @@ on: # Path-dependency metadata (including cuda_python_test_helpers) feeds the # solve, so it can break the source build without a pixi.toml edit. - "**/pyproject.toml" - - "cuda_bindings_13/build_hooks.py" + - "cuda_bindings*/build_hooks.py" - "cuda_core/build_hooks.py" - - "cuda_bindings_13/cuda/bindings/**" # generated bindings sources - - "cuda_bindings_13/tests/cython/**" + - "cuda_bindings*/cuda/bindings/**" # generated bindings sources + - "cuda_bindings*/docs/**" + - "cuda_bindings*/tests/cython/**" - "cuda_core/tests/cython/**" + - "ci/tools/bindings_config.py" + - "ci/tools/compute_ci_plan.py" + - "ci/pyproject.toml" - "ci/versions.yml" - "ci/pixi-version.env" - ".github/actions/setup-pixi/action.yml" @@ -53,9 +57,9 @@ on: workflow_dispatch: inputs: cuda-env: - description: "pixi environment to test (cu13 or cu12)." + description: "Registered pixi CUDA ABI environment to test (empty selects current)." type: string - default: "cu13" + default: "" defaults: run: @@ -73,7 +77,7 @@ env: jobs: # ── PR guard: CPU-only build + import + placement smoke ── build-smoke: - name: "build smoke (cu13, linux-64, CPU)" + name: "build smoke (selected CUDA packages, linux-64, CPU)" if: >- github.repository_owner == 'nvidia' && (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') @@ -83,58 +87,176 @@ jobs: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - # Full history + tags so setuptools-scm derives the real (13.x) + # Full history + tags so setuptools-scm derives the real # package version; a shallow checkout yields 0.1.dev1, which trips - # cuda.core's "cuda.bindings 12.x or 13.x must be installed" guard. + # cuda.core's supported cuda.bindings-version guard. fetch-depth: 0 filter: blob:none # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true + - name: Install CI tool dependencies + run: python3 -m pip install -e ./ci + - name: Setup pixi uses: ./.github/actions/setup-pixi - - name: Source-build + import + cython-placement smoke + - name: Select CUDA environments env: - CUDA_ENV: ${{ inputs.cuda-env || 'cu13' }} + BASE_SHA: ${{ github.event.pull_request.base.sha || '' }} + EVENT_NAME: ${{ github.event_name }} + REQUESTED_CUDA_ENV: ${{ inputs.cuda-env || '' }} run: | - # pathfinder: pure-Python, no GPU. - pixi run -e "${CUDA_ENV}" test-pathfinder - - # bindings + core: force the source build (catches nvrtc/driver - # compile errors like #2182) and import them (catches ABI mismatches). - pixi run --manifest-path cuda_bindings_13 -e "${CUDA_ENV}" \ - python -c "import cuda.bindings.driver, cuda.bindings.nvrtc, cuda.bindings.runtime; print('bindings import OK')" - pixi run --manifest-path cuda_core -e "${CUDA_ENV}" \ - python -c "import cuda.core; print('core import OK')" - - # cython test extensions: build them and confirm each .so landed next - # to its .pyx in tests/cython (catches the placement regression #2180). - pixi run --manifest-path cuda_bindings_13 -e "${CUDA_ENV}" build-cython-tests - pixi run --manifest-path cuda_core -e "${CUDA_ENV}" build-cython-tests - for d in cuda_bindings_13/tests/cython cuda_core/tests/cython; do - if ! compgen -G "${d}/*.cpython-*.so" > /dev/null; then - echo "::error::no compiled cython test .so in ${d} (placement regression)" - exit 1 + bindings_packages=$(python3 -m ci.tools.bindings_config --package-roots) + selected_packages='[]' + docs_packages='[]' + + merge_packages() { + jq -cn --argjson left "$1" --argjson right "$2" \ + '$left + $right | unique_by(.package_root)' + } + + if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then + if [[ -n "${REQUESTED_CUDA_ENV}" ]]; then + selected_packages=$(jq -c --arg cuda_env "${REQUESTED_CUDA_ENV}" \ + '[.[] | select(.cuda_variant == $cuda_env)]' <<< "${bindings_packages}") + if [[ "${selected_packages}" == '[]' ]]; then + registered_envs=$(jq -r '[.[].cuda_variant] | join(", ")' <<< "${bindings_packages}") + echo "::error::cuda-env must be a registered pixi environment: ${registered_envs}" + exit 1 + fi + else + selected_packages=$(jq -c '[.[] | select(.release_status == "current")]' \ + <<< "${bindings_packages}") fi - done + else + merge_base=$(git merge-base HEAD "${BASE_SHA}") + workplan=$(python3 -m ci.tools.compute_ci_plan \ + --merge-base "${merge_base}" \ + --baseline-run-id pixi-source) + + # Keep package-specific work package-specific, while selecting the + # registered package for any ABI-level work. + selected_packages=$(jq -cn \ + --argjson registry "${bindings_packages}" \ + --argjson plan "${workplan}" ' + $registry + | map(. as $package | select( + ($plan.modules.bindings.package_roots[$package.package_root].needs_build // false) + or ($plan.modules.bindings.package_roots[$package.package_root].needs_test // false) + or ($plan.modules.python.package_roots[$package.package_root].needs_build // false) + or ($plan.modules.python.package_roots[$package.package_root].needs_test // false) + or ($plan.jobs.test_cuda_majors[$package.cuda_variant] // false) + )) + ') + + # Pixi manifests are deliberately ignored by the wheel planner. + # Add their package-local impact to its source/test decisions. The + # wheel planner also deliberately ignores documentation changes. + while IFS= read -r -d '' path; do + manifest_packages=$(jq -c --arg path "${path}" ' + [.[] as $package + | select( + $path == ($package.package_root + "/pixi.toml") + or $path == ($package.package_root + "/pixi.lock") + ) + | $package] + ' <<< "${bindings_packages}") + if [[ "${manifest_packages}" != '[]' ]]; then + selected_packages=$(merge_packages "${selected_packages}" "${manifest_packages}") + else + case "${path}" in + */pixi.toml|*/pixi.lock|pixi.toml|pixi.lock) + selected_packages=$(merge_packages "${selected_packages}" "${bindings_packages}") + ;; + esac + fi + + changed_docs_packages=$(jq -c --arg path "${path}" ' + [.[] as $package + | select($path | startswith($package.package_root + "/docs/")) + | $package] + ' <<< "${bindings_packages}") + if [[ "${changed_docs_packages}" != '[]' ]]; then + selected_packages=$(merge_packages "${selected_packages}" "${changed_docs_packages}") + docs_packages=$(merge_packages "${docs_packages}" "${changed_docs_packages}") + fi + done < <(git diff --no-renames --name-only -z "${merge_base}" HEAD) + fi + + if [[ "${selected_packages}" == '[]' ]]; then + echo "::error::no bindings package selected for source-build smoke tests" + exit 1 + fi + echo "BINDINGS_PACKAGES=${selected_packages}" | tee -a "$GITHUB_ENV" + { + echo '### Selected source builds' + jq -r '.[] | "- \(.package_root): CUDA \(.cuda_major), pixi \(.cuda_variant)"' <<< "$selected_packages" + } >> "$GITHUB_STEP_SUMMARY" + echo "BINDINGS_DOC_PACKAGES=${docs_packages}" | tee -a "$GITHUB_ENV" + + - name: Source-build + import + cython-placement smoke + run: | + while IFS= read -r bindings_package; do + BINDINGS_ROOT=$(jq -r '.package_root' <<< "${bindings_package}") + CUDA_ENV=$(jq -r '.cuda_variant' <<< "${bindings_package}") + echo "::group::Source-build ${BINDINGS_ROOT} (${CUDA_ENV})" + if [[ $(jq -r '.release_status' <<< "${bindings_package}") == maintenance ]]; then + python3 -m ci.tools.bindings_scm_version --package-root "${BINDINGS_ROOT}" --sha "$GITHUB_SHA" + fi + # Avoid carrying Cython outputs between bindings packages or CUDA ABIs. + rm -rf cuda_core/build/cython cuda_core/cython_debug + find cuda_core/cuda/core -type f -name '*.so' -delete + find "${BINDINGS_ROOT}/tests/cython" cuda_core/tests/cython \ + -maxdepth 1 -type f \( -name 'test_*.cpp' -o -name 'test_*.so' \) -delete + + # pathfinder: pure-Python, no GPU. + pixi run -e "${CUDA_ENV}" test-pathfinder + + # Force both source builds and import them to catch compile/ABI + # regressions such as #2182. cuda-core environments may use + # published bindings by design; wheel CI covers local pairing. + pixi run --manifest-path "${BINDINGS_ROOT}" -e "${CUDA_ENV}" \ + python -c "import cuda.bindings.driver, cuda.bindings.nvrtc, cuda.bindings.runtime; print('bindings import OK')" + pixi run --manifest-path cuda_core -e "${CUDA_ENV}" \ + python -c "import cuda.core; print('core import OK')" + pixi run --manifest-path "${BINDINGS_ROOT}" -e "${CUDA_ENV}" build-cython-tests + pixi run --manifest-path cuda_core -e "${CUDA_ENV}" build-cython-tests + + # Confirm each extension landed next to its .pyx (catches #2180). + for d in "${BINDINGS_ROOT}/tests/cython" cuda_core/tests/cython; do + if ! compgen -G "${d}/*.cpython-*.so" > /dev/null; then + echo "::error::no compiled cython test .so in ${d} (placement regression)" + exit 1 + fi + done + echo "::endgroup::" + done < <(jq -c '.[]' <<< "${BINDINGS_PACKAGES}") echo "cython test extensions placed correctly" + - name: Build changed bindings documentation + if: ${{ env.BINDINGS_DOC_PACKAGES != '[]' }} + run: | + while IFS= read -r bindings_package; do + bindings_root=$(jq -r '.package_root' <<< "${bindings_package}") + pixi run --manifest-path "${bindings_root}" -e docs build-docs + done < <(jq -c '.[]' <<< "${BINDINGS_DOC_PACKAGES}") + # ── Nightly guard: build artifacts must be CUDA-major aware ── # # Neither Cython nor setuptools tracks the CUDA major in its own up-to-date # check: Cython does not hash `compile_time_env`, and an editable install's # .so is named by the Python ABI tag alone. Before build_hooks keyed them, - # a cu13 build followed by a cu12 build in the same checkout failed while - # compiling cu13-generated C++ against CUDA 12 headers. + # a build for one ABI followed by another in the same checkout failed while + # compiling generated C++ against headers from the second ABI. # - # The round trip (not just cu13 -> cu12) is what catches the second half: - # coming back to cu13 must not silently reuse the cu12 extension. + # The round trip is what catches the second half: coming back to the current + # ABI must not silently reuse the other ABI's extension. # - # cuda_core only: cuda-bindings cannot be source-built in its cu12 - # environment at all, for reasons unrelated to stale artifacts. + # cuda_core only: not every bindings package can be source-built in every ABI + # environment, for reasons unrelated to stale artifacts. build-identity-roundtrip: - name: "cu13 -> cu12 -> cu13 round trip (linux-64, CPU)" + name: "current -> maintenance -> current round trip (linux-64, CPU)" if: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.repository_owner == 'nvidia' }} runs-on: ubuntu-latest timeout-minutes: 60 @@ -142,26 +264,36 @@ jobs: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - # Full history + tags so setuptools-scm derives the real (13.x) + # Full history + tags so setuptools-scm derives the real # package version; a shallow checkout yields 0.1.dev1, which trips - # cuda.core's "cuda.bindings 12.x or 13.x must be installed" guard. + # cuda.core's supported cuda.bindings-version guard. fetch-depth: 0 filter: blob:none # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true + - name: Install CI tool dependencies + run: python3 -m pip install -e ./ci + - name: Setup pixi uses: ./.github/actions/setup-pixi - - name: Build cu13, then cu12, then cu13 again in one checkout + - name: Build current, another ABI, then current again in one checkout run: | - for cuda_env in cu13 cu12 cu13; do + current_package=$(python3 -m ci.tools.bindings_config --release-status current) + bindings_packages=$(python3 -m ci.tools.bindings_config --package-roots) + current_env=$(jq -r '.cuda_variant' <<< "${current_package}") + other_env=$(jq -r --arg current_env "${current_env}" \ + '[.[] | select(.cuda_variant != $current_env) | .cuda_variant] | first // empty' \ + <<< "${bindings_packages}") + + for cuda_env in "${current_env}" "${other_env}" "${current_env}"; do echo "::group::${cuda_env}" pixi run --manifest-path cuda_core -e "${cuda_env}" \ python -c "import cuda.core; print('core import OK')" echo "::endgroup::" done - # The last build was cu13, and each major must have kept its own + # The last build was current, and each ABI must have kept its own # generated sources rather than overwriting the other's. # Stamp is ABI-scoped (.build-config.). Unset and gnu # both record as "gnu"; llvm records as "llvm". @@ -172,21 +304,21 @@ jobs: exit 1 fi stamp=$(<"${stamps[0]}") - if [[ ! "${stamp}" =~ ^cu13-(gnu|llvm)-(debug|opt)(-cov)?$ ]]; then - echo "::error::build stamp is '${stamp}', expected cu13-{gnu|llvm}-{debug|opt}" + if [[ ! "${stamp}" =~ ^${current_env}-(gnu|llvm)-(debug|opt)(-cov)?$ ]]; then + echo "::error::build stamp is '${stamp}', expected ${current_env}-{gnu|llvm}-{debug|opt}" exit 1 fi - suffix="${stamp#cu13-}" - for major in cu12 cu13; do - if [ ! -d "cuda_core/build/cython/${major}-${suffix}" ]; then - echo "::error::no ${major}-${suffix} generated-source directory" + suffix="${stamp#"${current_env}-"}" + for cuda_env in "${other_env}" "${current_env}"; do + if [ ! -d "cuda_core/build/cython/${cuda_env}-${suffix}" ]; then + echo "::error::no ${cuda_env}-${suffix} generated-source directory" exit 1 fi done # ── Nightly: full `pixi run test` on a GPU runner ── full-test: - name: "pixi run test (${{ inputs.cuda-env || 'cu13' }}, linux-64, GPU)" + name: "pixi run test (${{ inputs.cuda-env || 'current' }}, linux-64, GPU)" if: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.repository_owner == 'nvidia' }} runs-on: "linux-amd64-gpu-l4-latest-1" # same label scheme as test-wheel-linux.yml timeout-minutes: 90 @@ -203,21 +335,41 @@ jobs: run: | apt-get update # ca-certificates + git for checkout; libgl1/libegl1 for pyglet - # (pulled in by the test env). pixi itself is installed by setup-pixi. + # (pulled in by the test env). PyYAML and packaging drive the + # bindings registry resolver; pixi itself is installed by setup-pixi. apt-get install -y --no-install-recommends \ - ca-certificates git libgl1 libegl1 + ca-certificates git jq libgl1 libegl1 python3 python3-packaging python3-yaml - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - # Full history + tags so setuptools-scm derives the real (13.x) + # Full history + tags so setuptools-scm derives the real # package version; a shallow checkout yields 0.1.dev1, which trips - # cuda.core's "cuda.bindings 12.x or 13.x must be installed" guard. + # cuda.core's supported cuda.bindings-version guard. fetch-depth: 0 filter: blob:none # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true + - name: Select CUDA environment + env: + REQUESTED_CUDA_ENV: ${{ inputs.cuda-env || '' }} + run: | + if [[ -n "${REQUESTED_CUDA_ENV}" ]]; then + bindings_packages=$(python3 -m ci.tools.bindings_config --package-roots) + if ! jq -e --arg cuda_env "${REQUESTED_CUDA_ENV}" \ + 'any(.[]; .cuda_variant == $cuda_env)' <<< "${bindings_packages}" > /dev/null; then + registered_envs=$(jq -r '[.[].cuda_variant] | join(", ")' <<< "${bindings_packages}") + echo "::error::cuda-env must be a registered pixi environment: ${registered_envs}" + exit 1 + fi + cuda_env="${REQUESTED_CUDA_ENV}" + else + current_package=$(python3 -m ci.tools.bindings_config --release-status current) + cuda_env=$(jq -r '.cuda_variant' <<< "${current_package}") + fi + echo "CUDA_ENV=${cuda_env}" | tee -a "$GITHUB_ENV" + - name: Setup proxy cache uses: nv-gha-runners/setup-proxy-cache@main continue-on-error: true @@ -226,4 +378,4 @@ jobs: uses: ./.github/actions/setup-pixi - name: pixi run test - run: pixi run -e "${{ inputs.cuda-env || 'cu13' }}" test + run: pixi run -e "${CUDA_ENV}" test diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 577e08c93b3..91ee5fe1f58 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -20,18 +20,25 @@ jobs: if: ${{ github.repository_owner == 'nvidia' }} runs-on: ubuntu-latest outputs: + BINDINGS_ROOT: ${{ steps.get-vars.outputs.bindings_root }} CUDA_VER: ${{ steps.get-vars.outputs.cuda_ver }} steps: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Get CUDA version + - name: Install CI tool dependencies + run: python3 -m pip install -e ./ci + - name: Resolve current CUDA bindings package id: get-vars run: | - cuda_ver=$(yq '.cuda.build.version' ci/versions.yml) - echo "cuda_ver=$cuda_ver" >> $GITHUB_OUTPUT + set -euo pipefail + current=$(python3 -m ci.tools.bindings_config --release-status current) + { + echo "bindings_root=$(jq -r '.package_root' <<< "$current")" + echo "cuda_ver=$(jq -r '.toolkit_version' <<< "$current")" + } >> "$GITHUB_OUTPUT" coverage-linux: - name: Coverage (Linux) + name: Coverage ${{ needs.coverage-vars.outputs.BINDINGS_ROOT }} + core (Linux) needs: [coverage-vars] runs-on: "linux-amd64-gpu-a100-latest-1" permissions: @@ -43,6 +50,7 @@ jobs: env: HOST_PLATFORM: "linux-64" ARCH: "x86_64" + BINDINGS_ROOT: ${{ needs.coverage-vars.outputs.BINDINGS_ROOT }} CUDA_VER: ${{ needs.coverage-vars.outputs.CUDA_VER }} # Our self-hosted runners require a container # TODO: use a different (nvidia?) container @@ -91,10 +99,13 @@ jobs: - name: Set environment variables env: - BUILD_CUDA_VER: ${{ env.CUDA_VER }} + BINDINGS_SOURCE: local + BINDINGS_SOURCE_DIR: ${{ env.BINDINGS_ROOT }} + DEFAULT_BINDINGS_SOURCE_DIR: ${{ env.BINDINGS_ROOT }} CUDA_VER: ${{ env.CUDA_VER }} HOST_PLATFORM: ${{ env.HOST_PLATFORM }} LOCAL_CTK: ${{ env.LOCAL_CTK }} + PATHFINDER_SOURCE: artifact PY_VER: ${{ env.PY_VER }} SHA: ${{ github.sha }} run: | @@ -133,8 +144,16 @@ jobs: run: | export PIP_BUILD_CONSTRAINT="$(pwd)/wheel-constraints/cuda-bindings.txt" export PIP_CONSTRAINT="${PIP_BUILD_CONSTRAINT}" - .venv/bin/pip wheel -v --no-deps ./cuda_bindings_13 -w ./wheels/ - .venv/bin/pip install -v ./wheels/cuda_bindings*.whl --group ./cuda_bindings_13/pyproject.toml:test + .venv/bin/pip wheel -v --no-deps "./${BINDINGS_ROOT}" -w ./wheels/ + bindings_wheels=(./wheels/cuda_bindings*.whl) + test "${#bindings_wheels[@]}" -eq 1 + test -f "${bindings_wheels[0]}" + bindings_pyproject="./${BINDINGS_ROOT}/pyproject.toml" + if grep -q '^\[dependency-groups\][[:space:]]*$' "${bindings_pyproject}"; then + .venv/bin/python -m pip install "${bindings_wheels[0]}" --group "${bindings_pyproject}:test" + else + .venv/bin/python -m pip install "${bindings_wheels[0]}[test]" + fi - name: Constrain cuda-core to the local cuda-bindings wheel run: | @@ -179,7 +198,7 @@ jobs: continue-on-error: true run: | cd $INSTALL_ROOT - $REPO_ROOT/.venv/bin/pytest -v --cov=./cuda --cov-append --cov-context=test --cov-config=$REPO_ROOT/.coveragerc $REPO_ROOT/cuda_bindings_13/tests + $REPO_ROOT/.venv/bin/pytest -v --cov=./cuda --cov-append --cov-context=test --cov-config=$REPO_ROOT/.coveragerc "$REPO_ROOT/${BINDINGS_ROOT}/tests" - name: Run cuda.core tests continue-on-error: true @@ -212,7 +231,7 @@ jobs: # Build Windows wheels on GitHub-hosted runner (has VS, no GPU) build-wheel-windows: - name: Build Wheels (Windows) + name: Build ${{ needs.coverage-vars.outputs.BINDINGS_ROOT }} + core for coverage (Windows) needs: [coverage-vars] runs-on: windows-2022 permissions: @@ -223,6 +242,7 @@ jobs: env: HOST_PLATFORM: "win-64" CUDA_PYTHON_COVERAGE: "1" + BINDINGS_ROOT: ${{ needs.coverage-vars.outputs.BINDINGS_ROOT }} CUDA_VER: ${{ needs.coverage-vars.outputs.CUDA_VER }} steps: - name: Harden OS certificate trust (eMudhra/emSign CA stopgap) @@ -275,8 +295,7 @@ jobs: run: | export PIP_BUILD_CONSTRAINT="$(cygpath -w "$(pwd)/wheel-constraints/cuda-bindings.txt")" export PIP_CONSTRAINT="${PIP_BUILD_CONSTRAINT}" - cd cuda_bindings_13 - ../.venv/Scripts/pip wheel -v --no-deps . -w ../wheels/ + .venv/Scripts/pip wheel -v --no-deps "./${BINDINGS_ROOT}" -w ./wheels/ - name: Constrain cuda.core to the local cuda.bindings wheel run: | @@ -331,7 +350,7 @@ jobs: # Run coverage tests on self-hosted GPU runner (no VS needed, installs pre-built wheels) coverage-windows: - name: Coverage (Windows) + name: Coverage ${{ needs.coverage-vars.outputs.BINDINGS_ROOT }} + core (Windows) needs: [coverage-vars, build-wheel-windows] runs-on: "windows-amd64-gpu-a100-latest-1" permissions: @@ -341,6 +360,7 @@ jobs: HOST_PLATFORM: "win-64" ARCH: "amd64" CUDA_PYTHON_COVERAGE: "1" + BINDINGS_ROOT: ${{ needs.coverage-vars.outputs.BINDINGS_ROOT }} CUDA_VER: ${{ needs.coverage-vars.outputs.CUDA_VER }} defaults: run: @@ -411,7 +431,15 @@ jobs: run: | .venv/Scripts/pip install coverage pytest-cov Cython .venv/Scripts/pip install --group ./cuda_pathfinder/pyproject.toml:test - .venv/Scripts/pip install --group ./cuda_bindings_13/pyproject.toml:test + bindings_wheels=(./wheels/cuda_bindings*.whl) + test "${#bindings_wheels[@]}" -eq 1 + test -f "${bindings_wheels[0]}" + bindings_pyproject="./${BINDINGS_ROOT}/pyproject.toml" + if grep -q '^\[dependency-groups\][[:space:]]*$' "${bindings_pyproject}"; then + .venv/Scripts/python -m pip install "${bindings_wheels[0]}" --group "${bindings_pyproject}:test" + else + .venv/Scripts/python -m pip install "${bindings_wheels[0]}[test]" + fi .venv/Scripts/pip install --group ./cuda_core/pyproject.toml:test - name: Get install root @@ -436,7 +464,7 @@ jobs: --cwd "${{ steps.install-root.outputs.INSTALL_ROOT }}" \ -v --cov=./cuda --cov-append --cov-context=test \ --cov-config="$GITHUB_WORKSPACE/.coveragerc" \ - "$GITHUB_WORKSPACE/cuda_bindings_13/tests" + "$GITHUB_WORKSPACE/${BINDINGS_ROOT}/tests" - name: Run cuda.core tests (with 8MB stack) continue-on-error: true diff --git a/.github/workflows/test-wheel-linux.yml b/.github/workflows/test-wheel-linux.yml index c5266302400..8d83d975326 100644 --- a/.github/workflows/test-wheel-linux.yml +++ b/.github/workflows/test-wheel-linux.yml @@ -13,7 +13,8 @@ on: host-platform: type: string required: true - build-ctk-ver: + bindings-config: + description: Normalized CUDA bindings package-root registry JSON. type: string required: true matrix_filter: @@ -52,17 +53,24 @@ defaults: jobs: compute-matrix: + if: >- + ${{ inputs.workplan == '' || + contains(fromJSON(inputs.workplan).jobs.test_cuda_majors.*, true) }} runs-on: ubuntu-latest env: + BINDINGS_CONFIG: ${{ inputs.bindings-config }} BUILD_TYPE: ${{ inputs.build-type }} + WORKPLAN: ${{ inputs.workplan }} + TEST_MODE: ${{ inputs.test-mode }} ARCH: ${{ (inputs.host-platform == 'linux-64' && 'amd64') || (inputs.host-platform == 'linux-aarch64' && 'arm64') }} outputs: MATRIX: ${{ steps.compute-matrix.outputs.MATRIX }} - OLD_BRANCH: ${{ steps.compute-matrix.outputs.OLD_BRANCH }} steps: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ inputs.sha || github.sha }} - name: Validate Test Type run: | @@ -83,27 +91,95 @@ jobs: # Read base matrix from YAML file for the specific architecture TEST_MATRIX=$(yq -o json ".linux[\"${MATRIX_TYPE}\"] | map(select(.ARCH == \"${ARCH}\"))" ci/test-matrix.yml) + BINDINGS_PACKAGES=$(jq -c '.package_roots' <<< "$BINDINGS_CONFIG") + CURRENT_BINDINGS_SOURCE_DIR=$(jq -r ' + .[] | select(.release_status == "current") | .package_root + ' <<< "$BINDINGS_PACKAGES") + + if [[ -z "$WORKPLAN" ]]; then + TEST_CUDA_MAJORS=$(jq -c ' + [.[].cuda_variant] | map({key: ., value: true}) | from_entries + ' <<< "$BINDINGS_PACKAGES") + PATHFINDER_SOURCE=artifact + else + TEST_CUDA_MAJORS=$(jq -c '.jobs.test_cuda_majors' <<< "$WORKPLAN") + PATHFINDER_SOURCE=$(jq -r '.sources.pathfinder' <<< "$WORKPLAN") + fi + # Apply matrix filter; reject custom DRIVER + FLAVOR=wsl (the # in-container driver swap doesn't work under WSL); add a # RUNNER_DRIVER field that maps any custom version back to # 'latest' (the install script swaps the driver itself, so we # need to land on the runner that ships with the most recent # pre-installed driver); wrap in include structure. - MATRIX=$(echo "$TEST_MATRIX" | jq -c '${{ inputs.matrix_filter }} | if any(.[]; .DRIVER != "latest" and .DRIVER != "earliest" and .FLAVOR == "wsl") then "Error: custom DRIVER is not supported with FLAVOR=wsl\n" | halt_error(1) else . end | map(. + {RUNNER_DRIVER: (if .DRIVER == "latest" or .DRIVER == "earliest" then .DRIVER else "latest" end)}) | if (. | length) > 0 then {include: .} else "Error: Empty matrix\n" | halt_error(1) end') + MATRIX=$(echo "$TEST_MATRIX" | jq -c \ + --argjson test_cuda_majors "$TEST_CUDA_MAJORS" \ + --argjson bindings_packages "$BINDINGS_PACKAGES" \ + --arg default_bindings_source_dir "$CURRENT_BINDINGS_SOURCE_DIR" \ + --arg pathfinder_source "$PATHFINDER_SOURCE" \ + --argjson workplan "${WORKPLAN:-null}" \ + --arg test_mode "$TEST_MODE" \ + '${{ inputs.matrix_filter }} + | map( + . as $row + | ("cu" + ($row.CUDA_VER | split(".")[0])) as $cuda_variant + | ($bindings_packages | map(select(.toolkit_version == $row.CUDA_VER)) | first) as $bindings_package + | $row + { + CUDA_VARIANT: $cuda_variant, + BINDINGS_SOURCE: (if $bindings_package == null then "floor" else "local" end), + BINDINGS_SOURCE_DIR: ($bindings_package.package_root // ""), + DEFAULT_BINDINGS_SOURCE_DIR: $default_bindings_source_dir, + PATHFINDER_SOURCE: $pathfinder_source + } + ) + | map(select($test_cuda_majors[.CUDA_VARIANT] == true)) + | map(. as $row | . + { + SUITES: (if $test_mode != "standard" then $test_mode else + [if $workplan == null or $workplan.modules.pathfinder.needs_test then "pathfinder" else empty end, + if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.bindings.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "bindings" + ($row.CUDA_VER | split(".")[0]) else empty end, + if $workplan == null or $workplan.modules.core.cuda_majors[$row.CUDA_VARIANT].needs_test then "core" + ($row.CUDA_VER | split(".")[0]) else empty end, + if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "python" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) + }) + | map(select(.SUITES != "")) + | if any(.[]; .DRIVER != "latest" and .DRIVER != "earliest" and .FLAVOR == "wsl") then "Error: custom DRIVER is not supported with FLAVOR=wsl\n" | halt_error(1) else . end + | map(. + {RUNNER_DRIVER: (if .DRIVER == "latest" or .DRIVER == "earliest" then .DRIVER else "latest" end)}) + | if (. | length) > 0 then {include: .} else "Error: Empty matrix after CUDA-major workplan filtering\n" | halt_error(1) end') + + # Compatibility nightly modes intentionally use published floor bindings. + # Standard PR/release runs must retain each selected local bindings line. + if [[ "$TEST_MODE" == "standard" && "$BUILD_TYPE" == "pull-request" ]]; then + jq -en --argjson packages "$BINDINGS_PACKAGES" \ + --argjson enabled "$TEST_CUDA_MAJORS" --argjson matrix "$MATRIX" \ + --argjson workplan "${WORKPLAN:-null}" ' + [$packages[] | . as $package + | select($enabled[.cuda_variant] == true) + | select($workplan == null or + $workplan.modules.bindings.package_roots[.package_root].needs_test or + $workplan.modules.python.package_roots[.package_root].needs_test) + | select(all($matrix.include[]; + .BINDINGS_SOURCE != "local" or .BINDINGS_SOURCE_DIR != $package.package_root)) + | .package_root] as $missing + | if $missing | length == 0 then true else + error("filtered test matrix omits required local-wheel coverage: \($missing | join(", "))") end + ' > /dev/null + fi - echo "MATRIX=${MATRIX}" | tee --append "${GITHUB_OUTPUT}" + { + echo '### Selected wheel test coverage' + echo '| Suites | Python | CTK | Toolkit source | Bindings source | GPU |' + echo '| --- | --- | --- | --- | --- | --- |' + jq -r '.include[] | "| \(.SUITES) | \(.PY_VER) | \(.CUDA_VER) | \(if .LOCAL_CTK == "1" then "local CTK" else "wheels" end) | \(if .BINDINGS_SOURCE == "local" then .BINDINGS_SOURCE_DIR else "published floor" end) | \(.GPU) |"' <<< "$MATRIX" + } >> "$GITHUB_STEP_SUMMARY" - # This job has yq already installed, so let's do it here - OLD_BRANCH=$(yq '.backport_branch' ci/versions.yml) - echo "OLD_BRANCH=${OLD_BRANCH}" >> "$GITHUB_OUTPUT" + echo "MATRIX=${MATRIX}" | tee --append "${GITHUB_OUTPUT}" test: env: TEST_PATHFINDER: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.pathfinder.needs_test }} - TEST_BINDINGS: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.bindings.needs_test }} - TEST_CORE: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.core.needs_test }} - TEST_PYTHON: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.python.needs_test }} - name: Python ${{ matrix.PY_VER }}, CUDA ${{ matrix.CUDA_VER }} (${{ (matrix.LOCAL_CTK == '1' && 'local') || 'wheels' }}), GPU ${{ matrix.GPU }}${{ matrix.GPU_COUNT != '1' && format(' (x{0})', matrix.GPU_COUNT) || '' }}${{ matrix.FLAVOR && format(', {0}', matrix.FLAVOR) || '' }}${{ matrix.ENV.TORCH_VER && format(', {0}+{1}', matrix.ENV.TORCH_VER, matrix.ENV.TORCH_CUDA) || '' }}${{ matrix.ENV.MODE == 'nightly-numba-cuda' && ', latest' || '' }} + TEST_BINDINGS: ${{ inputs.workplan == '' || (matrix.BINDINGS_SOURCE == 'local' && fromJSON(inputs.workplan).modules.bindings.package_roots[matrix.BINDINGS_SOURCE_DIR].needs_test) }} + TEST_CORE: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.core.cuda_majors[matrix.CUDA_VARIANT].needs_test }} + TEST_PYTHON: ${{ inputs.workplan == '' || (matrix.BINDINGS_SOURCE == 'local' && fromJSON(inputs.workplan).modules.python.package_roots[matrix.BINDINGS_SOURCE_DIR].needs_test) }} + name: ${{ matrix.SUITES }} / py${{ matrix.PY_VER }}, CTK${{ matrix.CUDA_VER }} (${{ (matrix.LOCAL_CTK == '1' && 'local CTK') || 'wheels' }}; bindings ${{ matrix.BINDINGS_SOURCE == 'local' && 'PR' || 'floor' }}), GPU ${{ matrix.GPU }}${{ matrix.GPU_COUNT != '1' && format(' (x{0})', matrix.GPU_COUNT) || '' }}${{ matrix.FLAVOR && format(', {0}', matrix.FLAVOR) || '' }}${{ matrix.ENV.TORCH_VER && format(', {0}+{1}', matrix.ENV.TORCH_VER, matrix.ENV.TORCH_CUDA) || '' }}${{ matrix.ENV.MODE == 'nightly-numba-cuda' && ', latest' || '' }} timeout-minutes: 60 needs: compute-matrix strategy: @@ -111,7 +187,8 @@ jobs: matrix: ${{ fromJSON(needs.compute-matrix.outputs.MATRIX) }} runs-on: "${{ matrix.FLAVOR || 'linux' }}-${{ matrix.ARCH }}-gpu-${{ matrix.GPU }}-${{ matrix.RUNNER_DRIVER }}-${{ matrix.GPU_COUNT }}" # The build stage could fail but we want the CI to keep moving. - if: ${{ github.repository_owner == 'nvidia' && !cancelled() }} + if: ${{ github.repository_owner == 'nvidia' && !cancelled() && + (inputs.workplan == '' || contains(fromJSON(inputs.workplan).jobs.test_cuda_majors.*, true)) }} # Our self-hosted runners require a container # TODO: use a different (nvidia?) container container: @@ -142,9 +219,8 @@ jobs: # for artifact fetching, graphics libs, g++ required for cffi in # example; util-linux for `nsenter` (custom-DRIVER rows re-exec # install_gpu_driver.sh onto the host through nsenter) - # yq: ci/tools/env-vars reads ci/versions.yml with it - dependencies: "jq wget libgl1 libegl1 g++ util-linux yq" - dependent_exes: "jq wget yq" + dependencies: "jq wget libgl1 libegl1 g++ util-linux" + dependent_exes: "jq wget" - name: Checkout driver install scripts (workflow revision) if: ${{ matrix.DRIVER != 'latest' && matrix.DRIVER != 'earliest' }} @@ -168,10 +244,13 @@ jobs: - name: Set environment variables env: - BUILD_CUDA_VER: ${{ inputs.build-ctk-ver }} + BINDINGS_SOURCE: ${{ matrix.BINDINGS_SOURCE }} + BINDINGS_SOURCE_DIR: ${{ matrix.BINDINGS_SOURCE_DIR }} + DEFAULT_BINDINGS_SOURCE_DIR: ${{ matrix.DEFAULT_BINDINGS_SOURCE_DIR }} CUDA_VER: ${{ matrix.CUDA_VER }} HOST_PLATFORM: ${{ inputs.host-platform }} LOCAL_CTK: ${{ matrix.LOCAL_CTK }} + PATHFINDER_SOURCE: ${{ matrix.PATHFINDER_SOURCE }} PY_VER: ${{ matrix.PY_VER }} SHA: ${{ inputs.sha || github.sha }} SKIP_BINDINGS_TEST_OVERRIDE: ${{ env.TEST_BINDINGS != 'true' && '1' || '0' }} @@ -184,7 +263,8 @@ jobs: run: echo "$MATRIX_ENV" | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> "$GITHUB_ENV" - name: Download cuda-pathfinder build artifacts - if: ${{ env.TEST_PATHFINDER == 'true' || env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true' }} + if: ${{ (env.TEST_PATHFINDER == 'true' || env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && + env.PATHFINDER_SOURCE == 'artifact' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: name: cuda-pathfinder-wheel @@ -193,17 +273,17 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Download cuda-python build artifacts - if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'main' }} + if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'local' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: - name: cuda-python-wheel + name: ${{ env.CUDA_PYTHON_ARTIFACT_NAME }} path: . run-id: ${{ inputs.run-id || github.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: Download cuda.bindings build artifacts if: ${{ (env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && - env.BINDINGS_SOURCE == 'main' }} + env.BINDINGS_SOURCE == 'local' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} @@ -211,64 +291,15 @@ jobs: run-id: ${{ inputs.run-id || github.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Download cuda-python & cuda.bindings build artifacts from the prior branch - if: ${{ (env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && - env.BINDINGS_SOURCE == 'backport' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # See https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian-ubuntu-linux-raspberry-pi-os-apt. - # gh is needed for artifact fetching. - mkdir -p -m 755 /etc/apt/keyrings \ - && out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \ - && cat $out | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \ - && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ - && apt update \ - && apt install gh -y - - OLD_BRANCH=${{ needs.compute-matrix.outputs.OLD_BRANCH }} - OLD_ARTIFACT_PATTERN="cuda-bindings-python${PYTHON_VERSION_FORMATTED}-cuda*-${{ inputs.host-platform }}-*[0-9a-f]" - LOOKUP_ARGS=( - --branch "${OLD_BRANCH}" - --artifact "${OLD_ARTIFACT_PATTERN}" - ) - if ${{ env.TEST_PYTHON == 'true' }}; then - LOOKUP_ARGS+=(--artifact cuda-python-wheel) - fi - LATEST_PRIOR_RUN_ID=$(./ci/tools/lookup-run-id \ - "${LOOKUP_ARGS[@]}" NVIDIA/cuda-python "CI") - - gh run download \ - "${LATEST_PRIOR_RUN_ID}" \ - -p "${OLD_ARTIFACT_PATTERN}" \ - -R NVIDIA/cuda-python - OLD_ARTIFACT_DIR=$(compgen -G "${OLD_ARTIFACT_PATTERN}") - test -d "${OLD_ARTIFACT_DIR}" - ls -al "${OLD_ARTIFACT_DIR}" - mkdir -p "${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}" - mv "${OLD_ARTIFACT_DIR}"/*.whl "${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}"/ - rmdir "${OLD_ARTIFACT_DIR}" - - if ${{ env.TEST_PYTHON == 'true' }}; then - gh run download \ - "${LATEST_PRIOR_RUN_ID}" \ - -p cuda-python-wheel \ - -R NVIDIA/cuda-python - ls -al cuda-python-wheel - mv cuda-python-wheel/*.whl . - rmdir cuda-python-wheel - fi - - name: Display structure of downloaded cuda-python artifacts - if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE != 'floor' }} + if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'local' }} run: | pwd ls -lah cuda_python*.whl cuda_pathfinder/ - name: Display structure of downloaded cuda.bindings artifacts if: ${{ (env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && - env.BINDINGS_SOURCE != 'floor' }} + env.BINDINGS_SOURCE == 'local' }} run: | pwd ls -lahR $CUDA_BINDINGS_ARTIFACTS_DIR @@ -307,7 +338,7 @@ jobs: if: ${{ env.TEST_CORE == 'true' && env.SKIP_CYTHON_TEST == '0' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: - name: ${{ env.CUDA_CORE_ARTIFACT_NAME }}-tests + name: ${{ env.CUDA_CORE_CYTHON_TEST_ARTIFACT_NAME }} path: ${{ env.CUDA_CORE_CYTHON_TESTS_DIR }} run-id: ${{ inputs.run-id || github.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} @@ -401,22 +432,25 @@ jobs: run: run-tests core - name: Ensure cuda-python installable - if: ${{ inputs.test-mode == 'standard' && env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'main' }} + if: ${{ inputs.test-mode == 'standard' && env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'local' }} + env: + LOCAL_CTK: ${{ matrix.LOCAL_CTK }} + shell: bash --noprofile --norc -xeuo pipefail {0} run: | - # Package suites install their own dependencies. A metapackage-only - # run has no preceding suite, so install the exact local internal - # wheels in one transaction while resolving released dependencies - # such as cuda-core from the package index. - if ${{ env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' }}; then + # CUDA 13's metapackage also requires Core. A bindings-only release + # must resolve published Core while preserving the selected wheels. + if [[ "$TEST_CORE" == true || ("$TEST_BINDINGS" == true && "$TEST_CUDA_MAJOR" == 12) ]]; then dependency_args=(--no-deps) else - dependency_args=( - ./cuda_pathfinder/cuda_pathfinder-*.whl - "${CUDA_BINDINGS_ARTIFACTS_DIR}"/cuda_bindings-*.whl - ) + dependency_args=("${CUDA_BINDINGS_ARTIFACTS_DIR}"/cuda_bindings-*.whl) + if [[ "$PATHFINDER_SOURCE" == artifact ]]; then + dependency_args+=(./cuda_pathfinder/cuda_pathfinder-*.whl) + else + dependency_args+=("$(python -c 'from importlib.metadata import version; print("cuda-pathfinder==" + version("cuda-pathfinder"))')") + fi fi python_requirements=(cuda_python*.whl) - if [[ "${{ matrix.LOCAL_CTK }}" != 1 ]]; then + if [[ "$LOCAL_CTK" != 1 ]]; then python_requirements=("${python_requirements[@]/%/[all]}") fi pip install --only-binary=:all: "${dependency_args[@]}" "${python_requirements[@]}" diff --git a/.github/workflows/test-wheel-windows.yml b/.github/workflows/test-wheel-windows.yml index 0b8f2802f3b..8c6fa97caa4 100644 --- a/.github/workflows/test-wheel-windows.yml +++ b/.github/workflows/test-wheel-windows.yml @@ -13,7 +13,8 @@ on: host-platform: type: string required: true - build-ctk-ver: + bindings-config: + description: Normalized CUDA bindings package-root registry JSON. type: string required: true matrix_filter: @@ -48,18 +49,26 @@ on: jobs: compute-matrix: + if: >- + ${{ inputs.workplan == '' || + contains(fromJSON(inputs.workplan).jobs.test_cuda_majors.*, true) }} runs-on: ubuntu-latest defaults: run: shell: bash --noprofile --norc -xeuo pipefail {0} env: + BINDINGS_CONFIG: ${{ inputs.bindings-config }} BUILD_TYPE: ${{ inputs.build-type }} + WORKPLAN: ${{ inputs.workplan }} + TEST_MODE: ${{ inputs.test-mode }} ARCH: ${{ (inputs.host-platform == 'win-64' && 'amd64') }} outputs: MATRIX: ${{ steps.compute-matrix.outputs.MATRIX }} steps: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ inputs.sha || github.sha }} - name: Validate Test Type run: | @@ -79,28 +88,100 @@ jobs: # Read base matrix from YAML file for the specific architecture TEST_MATRIX=$(yq -o json ".windows[\"${MATRIX_TYPE}\"] | map(select(.ARCH == \"${ARCH}\"))" ci/test-matrix.yml) + BINDINGS_PACKAGES=$(jq -c '.package_roots' <<< "$BINDINGS_CONFIG") + CURRENT_BINDINGS_SOURCE_DIR=$(jq -r ' + .[] | select(.release_status == "current") | .package_root + ' <<< "$BINDINGS_PACKAGES") + + if [[ -z "$WORKPLAN" ]]; then + TEST_CUDA_MAJORS=$(jq -c ' + [.[].cuda_variant] | map({key: ., value: true}) | from_entries + ' <<< "$BINDINGS_PACKAGES") + PATHFINDER_SOURCE=artifact + else + TEST_CUDA_MAJORS=$(jq -c '.jobs.test_cuda_majors' <<< "$WORKPLAN") + PATHFINDER_SOURCE=$(jq -r '.sources.pathfinder' <<< "$WORKPLAN") + fi + # Apply matrix filter; add a RUNNER_DRIVER field that maps any # custom DRIVER version back to 'latest' (install_gpu_driver.ps1 # swaps the driver itself, so the runner must be the one that # ships the most recent pre-installed driver); wrap in include. - MATRIX=$(echo "$TEST_MATRIX" | jq -c '${{ inputs.matrix_filter }} | map(. + {RUNNER_DRIVER: (if .DRIVER == "latest" or .DRIVER == "earliest" then .DRIVER else "latest" end)}) | if (. | length) > 0 then {include: .} else "Error: Empty matrix\n" | halt_error(1) end') + MATRIX=$(echo "$TEST_MATRIX" | jq -c \ + --argjson test_cuda_majors "$TEST_CUDA_MAJORS" \ + --argjson bindings_packages "$BINDINGS_PACKAGES" \ + --arg default_bindings_source_dir "$CURRENT_BINDINGS_SOURCE_DIR" \ + --arg pathfinder_source "$PATHFINDER_SOURCE" \ + --argjson workplan "${WORKPLAN:-null}" \ + --arg test_mode "$TEST_MODE" \ + '${{ inputs.matrix_filter }} + | map( + . as $row + | ("cu" + ($row.CUDA_VER | split(".")[0])) as $cuda_variant + | ($bindings_packages | map(select(.toolkit_version == $row.CUDA_VER)) | first) as $bindings_package + | $row + { + CUDA_VARIANT: $cuda_variant, + BINDINGS_SOURCE: (if $bindings_package == null then "floor" else "local" end), + BINDINGS_SOURCE_DIR: ($bindings_package.package_root // ""), + DEFAULT_BINDINGS_SOURCE_DIR: $default_bindings_source_dir, + PATHFINDER_SOURCE: $pathfinder_source + } + ) + | map(select($test_cuda_majors[.CUDA_VARIANT] == true)) + | map(. as $row | . + { + SUITES: (if $test_mode != "standard" then $test_mode else + [if $workplan == null or $workplan.modules.pathfinder.needs_test then "pathfinder" else empty end, + if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.bindings.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "bindings" + ($row.CUDA_VER | split(".")[0]) else empty end, + if $workplan == null or $workplan.modules.core.cuda_majors[$row.CUDA_VARIANT].needs_test then "core" + ($row.CUDA_VER | split(".")[0]) else empty end, + if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "python" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) + }) + | map(select(.SUITES != "")) + | map(. + {RUNNER_DRIVER: (if .DRIVER == "latest" or .DRIVER == "earliest" then .DRIVER else "latest" end)}) + | if (. | length) > 0 then {include: .} else "Error: Empty matrix after CUDA-major workplan filtering\n" | halt_error(1) end') + + # Compatibility nightly modes intentionally use published floor bindings. + # Standard PR/release runs must retain each selected local bindings line. + if [[ "$TEST_MODE" == "standard" && "$BUILD_TYPE" == "pull-request" ]]; then + jq -en --argjson packages "$BINDINGS_PACKAGES" \ + --argjson enabled "$TEST_CUDA_MAJORS" --argjson matrix "$MATRIX" \ + --argjson workplan "${WORKPLAN:-null}" ' + [$packages[] | . as $package + | select($enabled[.cuda_variant] == true) + | select($workplan == null or + $workplan.modules.bindings.package_roots[.package_root].needs_test or + $workplan.modules.python.package_roots[.package_root].needs_test) + | select(all($matrix.include[]; + .BINDINGS_SOURCE != "local" or .BINDINGS_SOURCE_DIR != $package.package_root)) + | .package_root] as $missing + | if $missing | length == 0 then true else + error("filtered test matrix omits required local-wheel coverage: \($missing | join(", "))") end + ' > /dev/null + fi + + { + echo '### Selected wheel test coverage' + echo '| Suites | Python | CTK | Toolkit source | Bindings source | GPU |' + echo '| --- | --- | --- | --- | --- | --- |' + jq -r '.include[] | "| \(.SUITES) | \(.PY_VER) | \(.CUDA_VER) | \(if .LOCAL_CTK == "1" then "local CTK" else "wheels" end) | \(if .BINDINGS_SOURCE == "local" then .BINDINGS_SOURCE_DIR else "published floor" end) | \(.GPU) |"' <<< "$MATRIX" + } >> "$GITHUB_STEP_SUMMARY" echo "MATRIX=${MATRIX}" | tee --append "${GITHUB_OUTPUT}" test: env: TEST_PATHFINDER: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.pathfinder.needs_test }} - TEST_BINDINGS: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.bindings.needs_test }} - TEST_CORE: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.core.needs_test }} - TEST_PYTHON: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.python.needs_test }} - name: Python ${{ matrix.PY_VER }}, CUDA ${{ matrix.CUDA_VER }} (${{ (matrix.LOCAL_CTK == '1' && 'local') || 'wheels' }}), GPU ${{ matrix.GPU }}${{ matrix.GPU_COUNT != '1' && format(' (x{0})', matrix.GPU_COUNT) || '' }} (${{ matrix.DRIVER_MODE }})${{ matrix.ENV.TORCH_VER && format(', {0}+{1}', matrix.ENV.TORCH_VER, matrix.ENV.TORCH_CUDA) || '' }}${{ matrix.ENV.MODE == 'nightly-numba-cuda' && ', latest' || '' }} + TEST_BINDINGS: ${{ inputs.workplan == '' || (matrix.BINDINGS_SOURCE == 'local' && fromJSON(inputs.workplan).modules.bindings.package_roots[matrix.BINDINGS_SOURCE_DIR].needs_test) }} + TEST_CORE: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.core.cuda_majors[matrix.CUDA_VARIANT].needs_test }} + TEST_PYTHON: ${{ inputs.workplan == '' || (matrix.BINDINGS_SOURCE == 'local' && fromJSON(inputs.workplan).modules.python.package_roots[matrix.BINDINGS_SOURCE_DIR].needs_test) }} + name: ${{ matrix.SUITES }} / py${{ matrix.PY_VER }}, CTK${{ matrix.CUDA_VER }} (${{ (matrix.LOCAL_CTK == '1' && 'local CTK') || 'wheels' }}; bindings ${{ matrix.BINDINGS_SOURCE == 'local' && 'PR' || 'floor' }}), GPU ${{ matrix.GPU }}${{ matrix.GPU_COUNT != '1' && format(' (x{0})', matrix.GPU_COUNT) || '' }} (${{ matrix.DRIVER_MODE }})${{ matrix.ENV.TORCH_VER && format(', {0}+{1}', matrix.ENV.TORCH_VER, matrix.ENV.TORCH_CUDA) || '' }}${{ matrix.ENV.MODE == 'nightly-numba-cuda' && ', latest' || '' }} timeout-minutes: 60 # The build stage could fail but we want the CI to keep moving. needs: compute-matrix strategy: fail-fast: false matrix: ${{ fromJSON(needs.compute-matrix.outputs.MATRIX) }} - if: ${{ github.repository_owner == 'nvidia' && !cancelled() }} + if: ${{ github.repository_owner == 'nvidia' && !cancelled() && + (inputs.workplan == '' || contains(fromJSON(inputs.workplan).jobs.test_cuda_majors.*, true)) }} runs-on: "windows-${{ matrix.ARCH }}-gpu-${{ matrix.GPU }}-${{ matrix.RUNNER_DRIVER }}-${{ matrix.GPU_COUNT }}" steps: - name: Enable Git symlinks (Windows, must precede checkout) @@ -157,10 +238,13 @@ jobs: - name: Set environment variables env: - BUILD_CUDA_VER: ${{ inputs.build-ctk-ver }} + BINDINGS_SOURCE: ${{ matrix.BINDINGS_SOURCE }} + BINDINGS_SOURCE_DIR: ${{ matrix.BINDINGS_SOURCE_DIR }} + DEFAULT_BINDINGS_SOURCE_DIR: ${{ matrix.DEFAULT_BINDINGS_SOURCE_DIR }} CUDA_VER: ${{ matrix.CUDA_VER }} HOST_PLATFORM: ${{ inputs.host-platform }} LOCAL_CTK: ${{ matrix.LOCAL_CTK }} + PATHFINDER_SOURCE: ${{ matrix.PATHFINDER_SOURCE }} PY_VER: ${{ matrix.PY_VER }} SHA: ${{ inputs.sha || github.sha }} SKIP_BINDINGS_TEST_OVERRIDE: ${{ env.TEST_BINDINGS != 'true' && '1' || '0' }} @@ -175,7 +259,8 @@ jobs: run: echo "$MATRIX_ENV" | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> "$GITHUB_ENV" - name: Download cuda-pathfinder build artifacts - if: ${{ env.TEST_PATHFINDER == 'true' || env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true' }} + if: ${{ (env.TEST_PATHFINDER == 'true' || env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && + env.PATHFINDER_SOURCE == 'artifact' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: name: cuda-pathfinder-wheel @@ -184,17 +269,17 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Download cuda-python build artifacts - if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'main' }} + if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'local' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: - name: cuda-python-wheel + name: ${{ env.CUDA_PYTHON_ARTIFACT_NAME }} path: . run-id: ${{ inputs.run-id || github.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: Download cuda.bindings build artifacts if: ${{ (env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && - env.BINDINGS_SOURCE == 'main' }} + env.BINDINGS_SOURCE == 'local' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} @@ -202,55 +287,15 @@ jobs: run-id: ${{ inputs.run-id || github.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Download cuda-python & cuda.bindings build artifacts from the prior branch - if: ${{ (env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && - env.BINDINGS_SOURCE == 'backport' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash --noprofile --norc -xeuo pipefail {0} - run: | - OLD_BRANCH=$(yq '.backport_branch' ci/versions.yml) - OLD_ARTIFACT_PATTERN="cuda-bindings-python${PYTHON_VERSION_FORMATTED}-cuda*-${{ inputs.host-platform }}-*[0-9a-f]" - LOOKUP_ARGS=( - --branch "${OLD_BRANCH}" - --artifact "${OLD_ARTIFACT_PATTERN}" - ) - if ${{ env.TEST_PYTHON == 'true' }}; then - LOOKUP_ARGS+=(--artifact cuda-python-wheel) - fi - LATEST_PRIOR_RUN_ID=$(./ci/tools/lookup-run-id \ - "${LOOKUP_ARGS[@]}" NVIDIA/cuda-python "CI") - - gh run download \ - "${LATEST_PRIOR_RUN_ID}" \ - -p "${OLD_ARTIFACT_PATTERN}" \ - -R NVIDIA/cuda-python - OLD_ARTIFACT_DIR=$(compgen -G "${OLD_ARTIFACT_PATTERN}") - test -d "${OLD_ARTIFACT_DIR}" - ls -al "${OLD_ARTIFACT_DIR}" - mkdir -p "${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}" - mv "${OLD_ARTIFACT_DIR}"/*.whl "${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}"/ - rmdir "${OLD_ARTIFACT_DIR}" - - if ${{ env.TEST_PYTHON == 'true' }}; then - gh run download \ - "${LATEST_PRIOR_RUN_ID}" \ - -p cuda-python-wheel \ - -R NVIDIA/cuda-python - ls -al cuda-python-wheel - mv cuda-python-wheel/*.whl . - rmdir cuda-python-wheel - fi - - name: Display structure of downloaded cuda-python artifacts - if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE != 'floor' }} + if: ${{ env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'local' }} run: | Get-Location Get-ChildItem cuda_python*.whl | Select-Object Mode, LastWriteTime, Length, FullName - name: Display structure of downloaded cuda.bindings artifacts if: ${{ (env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' || env.TEST_PYTHON == 'true') && - env.BINDINGS_SOURCE != 'floor' }} + env.BINDINGS_SOURCE == 'local' }} run: | Get-Location Get-ChildItem -Recurse -Force $env:CUDA_BINDINGS_ARTIFACTS_DIR | Select-Object Mode, LastWriteTime, Length, FullName @@ -289,7 +334,7 @@ jobs: if: ${{ env.TEST_CORE == 'true' && env.SKIP_CYTHON_TEST == '0' }} uses: NVIDIA/cuda-python/.github/actions/download-artifact-retry@f20d661666a5c92b757748ca237d3592ac3e942f # introduced in #3037 with: - name: ${{ env.CUDA_CORE_ARTIFACT_NAME }}-tests + name: ${{ env.CUDA_CORE_CYTHON_TEST_ARTIFACT_NAME }} path: ${{ env.CUDA_CORE_CYTHON_TESTS_DIR }} run-id: ${{ inputs.run-id || github.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} @@ -370,25 +415,28 @@ jobs: run: run-tests core - name: Ensure cuda-python installable - if: ${{ inputs.test-mode == 'standard' && env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'main' }} + if: ${{ inputs.test-mode == 'standard' && env.TEST_PYTHON == 'true' && env.BINDINGS_SOURCE == 'local' }} + env: + LOCAL_CTK: ${{ matrix.LOCAL_CTK }} + shell: bash --noprofile --norc -xeuo pipefail {0} run: | - # Package suites install their own dependencies. A metapackage-only - # run has no preceding suite, so install the exact local internal - # wheels in one transaction while resolving released dependencies - # such as cuda-core from the package index. - if ('${{ env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true' }}' -eq 'true') { - $dependencyArgs = @('--no-deps') - } else { - $dependencyArgs = @( - (Get-Item ./cuda_pathfinder/cuda_pathfinder-*.whl).FullName - (Get-Item "$env:CUDA_BINDINGS_ARTIFACTS_DIR/cuda_bindings-*.whl").FullName - ) - } - $pythonRequirements = @((Get-Item ./cuda_python*.whl).FullName) - if ('${{ matrix.LOCAL_CTK }}' -ne '1') { - $pythonRequirements = @($pythonRequirements | ForEach-Object { "$($_)[all]" }) - } - pip install --only-binary=:all: @dependencyArgs @pythonRequirements + # CUDA 13's metapackage also requires Core. A bindings-only release + # must resolve published Core while preserving the selected wheels. + if [[ "$TEST_CORE" == true || ("$TEST_BINDINGS" == true && "$TEST_CUDA_MAJOR" == 12) ]]; then + dependency_args=(--no-deps) + else + dependency_args=("${CUDA_BINDINGS_ARTIFACTS_DIR}"/cuda_bindings-*.whl) + if [[ "$PATHFINDER_SOURCE" == artifact ]]; then + dependency_args+=(./cuda_pathfinder/cuda_pathfinder-*.whl) + else + dependency_args+=("$(python -c 'from importlib.metadata import version; print("cuda-pathfinder==" + version("cuda-pathfinder"))')") + fi + fi + python_requirements=(cuda_python*.whl) + if [[ "$LOCAL_CTK" != 1 ]]; then + python_requirements=("${python_requirements[@]/%/[all]}") + fi + pip install --only-binary=:all: "${dependency_args[@]}" "${python_requirements[@]}" - name: Install cuda.pathfinder extra wheels for testing if: ${{ inputs.test-mode == 'standard' && env.TEST_PATHFINDER == 'true' }} diff --git a/ci/tools/run-tests b/ci/tools/run-tests index 04a5fa689d3..e2e41cedb2a 100755 --- a/ci/tools/run-tests +++ b/ci/tools/run-tests @@ -38,9 +38,11 @@ fi test_module=${1} TEST_FT_GROUP=() +TEST_FT_REQUIREMENT=() PYTEST_PARALLEL_ARGS=() if python -c 'import sys; assert not sys._is_gil_enabled()' 2> /dev/null; then TEST_FT_GROUP=(--group test-ft) + TEST_FT_REQUIREMENT=(pytest-run-parallel==0.10.0) PYTEST_PARALLEL_ARGS=(--parallel-threads=4) fi @@ -49,8 +51,21 @@ fi # all wheels together in a single pip call further below. if [[ "${test_module}" != nightly-* ]]; then pushd ./cuda_pathfinder - echo "Installing pathfinder wheel" - pip install ./*.whl --group test "${TEST_FT_GROUP[@]}" + if [[ "${PATHFINDER_SOURCE:-}" == "artifact" ]]; then + echo "Installing pathfinder wheel from CI artifacts" + pathfinder_wheels=(./*.whl) + if [[ "${#pathfinder_wheels[@]}" -ne 1 || ! -f "${pathfinder_wheels[0]}" ]]; then + echo "Expected exactly one cuda-pathfinder wheel in $(pwd)" >&2 + exit 1 + fi + pip install "${pathfinder_wheels[0]}" --group test "${TEST_FT_GROUP[@]}" + elif [[ "${PATHFINDER_SOURCE:-}" == "published" && "${test_module}" == "bindings" ]]; then + echo "Installing published pathfinder for a focused bindings release" + pip install cuda-pathfinder --group test "${TEST_FT_GROUP[@]}" + else + echo "Error: PATHFINDER_SOURCE must be artifact, or published for bindings release tests; got ${PATHFINDER_SOURCE:-}" >&2 + exit 1 + fi popd fi @@ -68,15 +83,33 @@ if [[ "${test_module}" == "pathfinder" ]]; then popd elif [[ "${test_module}" == "bindings" ]]; then echo "Installing bindings wheel" - pushd ./cuda_bindings_13 - if [[ "${LOCAL_CTK}" == 1 ]]; then - pip install "${CUDA_BINDINGS_ARTIFACTS_DIR}"/*.whl --group test "${TEST_FT_GROUP[@]}" - else + pushd "./${CUDA_BINDINGS_ROOT}" + bindings_wheels=("${CUDA_BINDINGS_ARTIFACTS_DIR}"/*.whl) + if [[ "${#bindings_wheels[@]}" -ne 1 || ! -f "${bindings_wheels[0]}" ]]; then + echo "Expected exactly one cuda-bindings wheel in ${CUDA_BINDINGS_ARTIFACTS_DIR}" >&2 + exit 1 + fi + bindings_requirement="${bindings_wheels[0]}" + bindings_toolkit_requirement=() + if [[ "${LOCAL_CTK}" != 1 ]]; then TEST_CUDA_MAJOR_MINOR="$(cut -d '.' -f 1-2 <<< "${CUDA_VER}")" # Keep the wheel-installed Toolkit aligned with the matrix-selected minor; # newer minors can grow ABI structs beyond the size compiled into this wheel. - pip install $(ls "${CUDA_BINDINGS_ARTIFACTS_DIR}"/*.whl)[all] --group test "${TEST_FT_GROUP[@]}" \ - "cuda-toolkit==${TEST_CUDA_MAJOR_MINOR}.*" + bindings_toolkit_requirement=("cuda-toolkit==${TEST_CUDA_MAJOR_MINOR}.*") + fi + if grep -q '^\[dependency-groups\][[:space:]]*$' pyproject.toml; then + if [[ "${LOCAL_CTK}" != 1 ]]; then + bindings_requirement+="[all]" + fi + python -m pip install "${bindings_requirement}" --group pyproject.toml:test \ + "${TEST_FT_GROUP[@]}" "${bindings_toolkit_requirement[@]}" + else + bindings_extras="test" + if [[ "${LOCAL_CTK}" != 1 ]]; then + bindings_extras="all,test" + fi + python -m pip install "${bindings_requirement}[${bindings_extras}]" \ + "${TEST_FT_REQUIREMENT[@]}" "${bindings_toolkit_requirement[@]}" fi echo "Running bindings tests" ${SANITIZER_CMD} pytest -rsxXfE -v --randomly-dont-reorganize --exclude-warning-annotations "${PYTEST_PARALLEL_ARGS[@]}" --junitxml "${TEST_RESULTS_DIR}/junit-bindings.xml" tests/ | fold_pytest_log @@ -86,13 +119,13 @@ elif [[ "${test_module}" == "bindings" ]]; then popd elif [[ "${test_module}" == "core" || "${test_module}" == nightly-* ]]; then # Shared setup for core and nightly modes. - TEST_CUDA_MAJOR="$(cut -d '.' -f 1 <<< ${CUDA_VER})" + TEST_CUDA_MAJOR="$(cut -d '.' -f 1 <<< "${CUDA_VER}")" TEST_CUDA_MAJOR_MINOR="$(cut -d '.' -f 1-2 <<< "${CUDA_VER}")" # Resolve bindings based on BINDINGS_SOURCE (set by env-vars): - # main/backport → local wheel from artifacts dir - # floor → the oldest cuda-bindings that the cuda-core wheel under test - # supports, read from that wheel and installed from PyPI + # local → matching configured-package wheel from this run + # floor -> the oldest supported bindings, read from the Core wheel + # and installed from PyPI BINDINGS_ARGS=() if [[ "${BINDINGS_SOURCE}" == "floor" ]]; then CORE_WHL_FOR_FLOOR=("${CUDA_CORE_ARTIFACTS_DIR}"/*.whl) @@ -114,10 +147,19 @@ elif [[ "${test_module}" == "core" || "${test_module}" == nightly-* ]]; then fi if [[ "${test_module}" == nightly-* ]]; then + if [[ "${PATHFINDER_SOURCE:-}" != "artifact" ]]; then + echo "Error: nightly tests require PATHFINDER_SOURCE=artifact" >&2 + exit 1 + fi # Resolve pathfinder wheel to absolute path before pushd. # CUDA_BINDINGS_ARTIFACTS_DIR and CUDA_CORE_ARTIFACTS_DIR are already # absolute (set via realpath in env-vars). - PATHFINDER_WHL=($(realpath ./cuda_pathfinder/*.whl)) + pathfinder_wheels=(./cuda_pathfinder/*.whl) + if [[ "${#pathfinder_wheels[@]}" -ne 1 || ! -f "${pathfinder_wheels[0]}" ]]; then + echo "Expected exactly one cuda-pathfinder wheel in ./cuda_pathfinder" >&2 + exit 1 + fi + PATHFINDER_WHL=("$(realpath "${pathfinder_wheels[0]}")") fi if [[ "${test_module}" == "core" ]]; then @@ -143,8 +185,8 @@ elif [[ "${test_module}" == "core" || "${test_module}" == nightly-* ]]; then pip list echo "Running core tests" ${SANITIZER_CMD} pytest -rsxXfE -v --randomly-dont-reorganize --exclude-warning-annotations "${PYTEST_PARALLEL_ARGS[@]}" --junitxml "${TEST_RESULTS_DIR}/junit-core.xml" tests/ | fold_pytest_log - # Currently our CI always installs the latest bindings (from either major version). - # This is not compatible with the test requirements. + # Compiled Cython tests require the bindings used to build them. Older + # toolkit rows intentionally exercise published floor bindings instead. if [[ "${SKIP_CYTHON_TEST}" == 0 ]]; then ${SANITIZER_CMD} pytest -rsxXfE -v --randomly-dont-reorganize --exclude-warning-annotations "${PYTEST_PARALLEL_ARGS[@]}" --junitxml "${TEST_RESULTS_DIR}/junit-core-cython.xml" tests/cython | fold_pytest_log fi diff --git a/ci/tools/tests/test_pixi_lockfile_freshness_workflow.py b/ci/tools/tests/test_pixi_lockfile_freshness_workflow.py index d5f94837861..780f9bd87d7 100644 --- a/ci/tools/tests/test_pixi_lockfile_freshness_workflow.py +++ b/ci/tools/tests/test_pixi_lockfile_freshness_workflow.py @@ -7,10 +7,12 @@ import shlex import subprocess +import tomllib from pathlib import Path import pytest import yaml +from packaging.requirements import Requirement ROOT = Path(__file__).resolve().parents[3] WORKFLOWS = ROOT / ".github/workflows" @@ -110,11 +112,17 @@ def test_source_builds_and_tests_still_use_frozen_pixi(): assert any("pixi run" in step.get("run", "") for step in job["steps"]) -@pytest.mark.agent_authored(model="gpt-6") +@pytest.mark.agent_authored(model="gpt-6.1-sol") def test_nightly_ci_declares_workflow_test_dependencies(): workflow = _workflow("ci-nightly.yml") step = next(step for step in workflow["jobs"]["test-ci-tools-for-release"]["steps"] if "run" in step) install = next(line for line in step["run"].splitlines() if "pip install" in line) - dependencies = {argument.lower().split("==")[0] for argument in shlex.split(install)} + arguments = shlex.split(install) + if "./ci[test]" in arguments: + metadata = tomllib.loads((ROOT / "ci/pyproject.toml").read_text(encoding="utf-8"))["project"] + requirements = [*metadata["dependencies"], *metadata["optional-dependencies"]["test"]] + dependencies = {Requirement(requirement).name.lower() for requirement in requirements} + else: + dependencies = {argument.lower().split("==")[0] for argument in arguments} assert {"pytest", "pyyaml"} <= dependencies diff --git a/ci/tools/tests/test_test_sources.py b/ci/tools/tests/test_test_sources.py new file mode 100644 index 00000000000..e99c0ad4c16 --- /dev/null +++ b/ci/tools/tests/test_test_sources.py @@ -0,0 +1,340 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +from __future__ import annotations + +import os +import subprocess +import sys +import zipfile +from pathlib import Path + +import pytest + +from ci.tools.bindings_config import load_config + +REPO_ROOT = Path(__file__).resolve().parents[3] +RUN_TESTS = REPO_ROOT / "ci" / "tools" / "run-tests" +ENV_VARS = REPO_ROOT / "ci" / "tools" / "env-vars" + + +def _write_command(directory: Path, name: str, body: str) -> None: + path = directory / name + path.write_text(f"#!/usr/bin/env bash\nset -eu\n{body}\n", encoding="utf-8") + path.chmod(0o755) + + +def _run_tests_env(tmp_path: Path) -> tuple[dict[str, str], Path]: + fake_bin = tmp_path / "bin" + fake_bin.mkdir() + command_log = tmp_path / "commands.log" + _write_command( + fake_bin, + "python", + """ +if [[ "${1:-}" == "-c" ]]; then + exit 1 +fi +if [[ "${1:-}" == "ci/tools/cuda_core_bindings_floor.py" ]]; then + exec "$REAL_PYTHON" "$@" +fi +printf 'python %s\\n' "$*" >> "$COMMAND_LOG" +""".strip(), + ) + _write_command(fake_bin, "pip", 'printf \'pip %s\\n\' "$*" >> "$COMMAND_LOG"') + _write_command(fake_bin, "pytest", ":") + env = { + **os.environ, + "COMMAND_LOG": str(command_log), + "REAL_PYTHON": sys.executable, + "PATH": f"{fake_bin}{os.pathsep}{os.environ['PATH']}", + "CUDA_PATHFINDER_TEST_LOAD_NVIDIA_DYNAMIC_LIB_STRICTNESS": "see_what_works", + "CUDA_PATHFINDER_TEST_FIND_NVIDIA_HEADERS_STRICTNESS": "see_what_works", + "CUDA_PATHFINDER_TEST_FIND_NVIDIA_BITCODE_LIB_STRICTNESS": "see_what_works", + } + (tmp_path / "cuda_pathfinder").mkdir() + return env, command_log + + +def _run_env_vars( + tmp_path: Path, + *, + bindings_source: str, + pathfinder_source: str, + cuda_version: str = "13.3.0", + bindings_root: str = "cuda_bindings", +) -> subprocess.CompletedProcess[str]: + for relative in ( + f"{bindings_root}/dist", + f"{bindings_root}/tests/cython", + "cuda_core/dist", + "cuda_core/tests/cython", + "cuda_core/tests/test_binaries", + ): + (tmp_path / relative).mkdir(parents=True, exist_ok=True) + github_env = tmp_path / "github-env" + github_path = tmp_path / "github-path" + env = { + **os.environ, + "BINDINGS_SOURCE": bindings_source, + "CUDA_VER": cuda_version, + "GITHUB_ENV": str(github_env), + "GITHUB_PATH": str(github_path), + "HOST_PLATFORM": "linux-64", + "LOCAL_CTK": "0", + "PATHFINDER_SOURCE": pathfinder_source, + "PY_VER": "3.13", + "SHA": "abcdef", + "SKIP_BINDINGS_TEST_OVERRIDE": "0", + } + if bindings_source == "local": + env["BINDINGS_SOURCE_DIR"] = bindings_root + else: + env["DEFAULT_BINDINGS_SOURCE_DIR"] = bindings_root + return subprocess.run( # noqa: S603 - invokes the repository script under test + [str(ENV_VARS), "test"], + cwd=tmp_path, + env=env, + check=False, + capture_output=True, + text=True, + ) + + +def _read_github_env(path: Path) -> dict[str, str]: + return dict(line.split("=", 1) for line in path.read_text(encoding="utf-8").splitlines()) + + +@pytest.mark.agent_authored(model="gpt-5.6-sol") +def test_env_vars_rejects_unknown_mode() -> None: + result = subprocess.run( # noqa: S603 - invokes the repository script under test + [str(ENV_VARS), "unknown"], + check=False, + capture_output=True, + text=True, + ) + + assert result.returncode == 1 + assert "build mode must be build or test" in result.stderr + + +@pytest.mark.agent_authored(model="gpt-5.6") +def test_build_env_uses_registry_packages_without_generic_bindings_aliases(tmp_path: Path) -> None: + github_env = tmp_path / "github-env" + env = { + **os.environ, + "GITHUB_ENV": str(github_env), + "GITHUB_PATH": str(tmp_path / "github-path"), + "HOST_PLATFORM": "linux-64", + "PY_VER": "3.13", + "SHA": "abcdef0", + } + + result = subprocess.run( # noqa: S603 - invokes the repository script under test + [str(ENV_VARS), "build"], + cwd=REPO_ROOT, + env=env, + check=False, + capture_output=True, + text=True, + ) + + assert result.returncode == 0, result.stderr + values = _read_github_env(github_env) + config = load_config() + for status in ("current", "maintenance"): + package = config.package_for_release_status(status) + prefix = status.upper() + assert values[f"{prefix}_BINDINGS_ROOT"] == package.package_root + assert values[f"{prefix}_CUDA_VERSION"] == package.toolkit_version + assert values[f"{prefix}_CUDA_MAJOR"] == package.cuda_major + assert values[f"{prefix}_CUDA_VARIANT"] == package.cuda_variant + assert values[f"{prefix}_BINDINGS_ARTIFACT_NAME"].endswith("-abcdef0") + + assert ( + not { + "CUDA_BINDINGS_ARTIFACT_BASENAME", + "CUDA_BINDINGS_ARTIFACT_NAME", + "CUDA_BINDINGS_ARTIFACTS_DIR", + "CUDA_BINDINGS_CYTHON_TESTS_DIR", + } + & values.keys() + ) + + +@pytest.mark.parametrize("wheel_count", [0, 2]) +@pytest.mark.agent_authored(model="gpt-5.6") +def test_artifact_pathfinder_requires_exactly_one_wheel(tmp_path: Path, wheel_count: int) -> None: + env, _ = _run_tests_env(tmp_path) + env["PATHFINDER_SOURCE"] = "artifact" + for index in range(wheel_count): + (tmp_path / "cuda_pathfinder" / f"cuda_pathfinder-{index}.whl").touch() + + result = subprocess.run( # noqa: S603 - invokes the repository script under test + [str(RUN_TESTS), "pathfinder"], + cwd=tmp_path, + env=env, + check=False, + capture_output=True, + text=True, + ) + + assert result.returncode != 0 + assert "Expected exactly one cuda-pathfinder wheel" in result.stderr + + +@pytest.mark.agent_authored(model="gpt-5.6") +def test_artifact_pathfinder_installs_the_only_wheel(tmp_path: Path) -> None: + env, command_log = _run_tests_env(tmp_path) + env["PATHFINDER_SOURCE"] = "artifact" + wheel = tmp_path / "cuda_pathfinder" / "cuda_pathfinder-1.0-py3-none-any.whl" + wheel.touch() + + subprocess.run( # noqa: S603 - invokes the repository script under test + [str(RUN_TESTS), "pathfinder"], + cwd=tmp_path, + env=env, + check=True, + capture_output=True, + text=True, + ) + + assert f"pip install ./{wheel.name} --group test" in command_log.read_text(encoding="utf-8") + + +@pytest.mark.agent_authored(model="gpt-5.6") +def test_published_pathfinder_is_limited_to_bindings_release_tests(tmp_path: Path) -> None: + env, _ = _run_tests_env(tmp_path) + env["PATHFINDER_SOURCE"] = "published" + + result = subprocess.run( # noqa: S603 - invokes the repository script under test + [str(RUN_TESTS), "pathfinder"], + cwd=tmp_path, + env=env, + check=False, + capture_output=True, + text=True, + ) + + assert result.returncode != 0 + assert "published for bindings release tests" in result.stderr + + +@pytest.mark.agent_authored(model="gpt-5.6") +def test_published_pathfinder_supports_bindings_release_tests(tmp_path: Path) -> None: + env, command_log = _run_tests_env(tmp_path) + env.update( + CUDA_BINDINGS_ARTIFACTS_DIR=str(tmp_path / "bindings-artifacts"), + CUDA_BINDINGS_ROOT="cuda_bindings", + LOCAL_CTK="1", + PATHFINDER_SOURCE="published", + SANITIZER_CMD="", + SKIP_CYTHON_TEST="1", + ) + (tmp_path / "cuda_bindings").mkdir() + (tmp_path / "cuda_bindings" / "pyproject.toml").write_text("[dependency-groups]\ntest = []\n", encoding="utf-8") + (tmp_path / "bindings-artifacts").mkdir() + (tmp_path / "bindings-artifacts" / "cuda_bindings-13.3.whl").touch() + + subprocess.run( # noqa: S603 - invokes the repository script under test + [str(RUN_TESTS), "bindings"], + cwd=tmp_path, + env=env, + check=True, + capture_output=True, + text=True, + ) + + calls = command_log.read_text(encoding="utf-8").splitlines() + assert calls[0].startswith("pip install cuda-pathfinder --group test") + assert calls[1].startswith("python -m pip install ") + + +@pytest.mark.parametrize( + ("bindings_source", "cuda_version", "bindings_root", "expected_artifact"), + [ + ("local", "13.4.2", "cuda_bindings", "cuda-python-wheel-cuda13.4.2"), + ("local", "12.9.1", "cuda_bindings_12", "cuda-python-wheel-cuda12.9.1"), + ("floor", "13.0.2", "cuda_bindings", None), + ("floor", "12.6.3", "cuda_bindings", None), + ], +) +@pytest.mark.agent_authored(model="gpt-6-astra") +def test_cuda_python_artifact_name_exists_only_for_local_bindings( + tmp_path: Path, + bindings_source: str, + cuda_version: str, + bindings_root: str, + expected_artifact: str | None, +) -> None: + result = _run_env_vars( + tmp_path, + bindings_source=bindings_source, + pathfinder_source="artifact", + cuda_version=cuda_version, + bindings_root=bindings_root, + ) + + assert result.returncode == 0, result.stderr + github_env = _read_github_env(tmp_path / "github-env") + assert { + "CUDA_BINDINGS_ARTIFACT_BASENAME", + "CUDA_BINDINGS_ARTIFACT_NAME", + "CUDA_BINDINGS_ARTIFACTS_DIR", + "CUDA_BINDINGS_CYTHON_TESTS_DIR", + "CUDA_CORE_CYTHON_TEST_ARTIFACT_NAME", + } <= github_env.keys() + assert github_env["BINDINGS_SOURCE"] == bindings_source + assert github_env["CUDA_BINDINGS_ROOT"] == bindings_root + assert github_env["SKIP_CUDA_BINDINGS_TEST"] == ("1" if bindings_source == "floor" else "0") + assert github_env["SKIP_CYTHON_TEST"] == ("1" if bindings_source == "floor" else "0") + assert github_env["CUDA_CORE_CYTHON_TEST_ARTIFACT_NAME"].endswith(f"-cu{cuda_version.split('.')[0]}-tests") + if expected_artifact is None: + assert "CUDA_PYTHON_ARTIFACT_NAME" not in github_env + else: + assert github_env["CUDA_PYTHON_ARTIFACT_NAME"] == expected_artifact + + +@pytest.mark.agent_authored(model="gpt-6-astra") +@pytest.mark.parametrize(("cuda_version", "wheel_floor"), [("12.6.3", "12.9.9"), ("13.0.2", "13.4.2")]) +def test_core_install_uses_wheel_floor_with_older_toolkit(tmp_path: Path, cuda_version: str, wheel_floor: str) -> None: + env, command_log = _run_tests_env(tmp_path) + (tmp_path / "cuda_pathfinder" / "cuda_pathfinder-1.0-py3-none-any.whl").touch() + core_dist = tmp_path / "cuda_core" / "dist" + core_dist.mkdir(parents=True) + wheel = core_dist / "cuda_core-1.3.0-cp313-cp313-linux_x86_64.whl" + major = int(cuda_version.split(".")[0]) + with zipfile.ZipFile(wheel, "w") as archive: + archive.writestr( + "cuda_core-1.3.0.dist-info/METADATA", + f'Requires-Dist: cuda-bindings[all]>={wheel_floor},<{major + 1}; extra == "cu{major}"\n', + ) + tools = tmp_path / "ci" / "tools" + tools.mkdir(parents=True) + floor_script = REPO_ROOT / "ci" / "tools" / "cuda_core_bindings_floor.py" + (tools / floor_script.name).write_text(floor_script.read_text(encoding="utf-8"), encoding="utf-8") + env.update( + BINDINGS_SOURCE="floor", + CUDA_CORE_ARTIFACTS_DIR=str(core_dist), + CUDA_VER=cuda_version, + LOCAL_CTK="0", + PATHFINDER_SOURCE="artifact", + SANITIZER_CMD="", + SKIP_CYTHON_TEST="1", + ) + + result = subprocess.run( # noqa: S603 - repository script with install/test commands replaced by recording stubs + [str(RUN_TESTS), "core"], + cwd=tmp_path, + env=env, + check=False, + capture_output=True, + text=True, + ) + + assert result.returncode == 0, result.stderr + calls = command_log.read_text(encoding="utf-8").splitlines() + assert f"pip install cuda-bindings=={wheel_floor}" in calls + toolkit_minor = ".".join(cuda_version.split(".")[:2]) + assert any(f"cuda-toolkit=={toolkit_minor}.*" in call for call in calls) diff --git a/cuda_bindings_13/docs/build_docs.sh b/cuda_bindings_13/docs/build_docs.sh index 199ababce60..53d0e14d0ea 100755 --- a/cuda_bindings_13/docs/build_docs.sh +++ b/cuda_bindings_13/docs/build_docs.sh @@ -16,13 +16,12 @@ fi # SPHINX_CUDA_BINDINGS_VER is used to create a subdir under build/html # (the Makefile file for sphinx-build also honors it if defined). -# If there's a post release (ex: .post1) we don't want it to show up in the -# version selector or directory structure. +# Post releases reuse their base release directory, while prerelease and +# development releases remain distinct so they cannot overwrite stable docs. if [[ -z "${SPHINX_CUDA_BINDINGS_VER}" ]]; then export SPHINX_CUDA_BINDINGS_VER=$(python -c "from importlib.metadata import version; \ - ver = '.'.join(str(version('cuda-bindings')).split('.')[:3]); \ - print(ver)" \ - | awk -F'+' '{print $1}') + ver = str(version('cuda-bindings')).split('+', 1)[0]; \ + print(ver if '.dev' in ver else ver.split('.post', 1)[0])") fi if [[ "${LATEST_ONLY}" == "1" && -z "${BUILD_PREVIEW:-}" && -z "${BUILD_LATEST:-}" ]]; then diff --git a/cuda_bindings_13/docs/source/install.rst b/cuda_bindings_13/docs/source/install.rst index 2c8213816d7..54adde64bb1 100644 --- a/cuda_bindings_13/docs/source/install.rst +++ b/cuda_bindings_13/docs/source/install.rst @@ -108,9 +108,9 @@ obtain the most recent build, use the following commands: Replace ``python312`` with your Python version (e.g. ``python311``, ``python313``, ``python314``, ``python314t``, ``python315``, ``python315t``). For aarch64, replace ``linux-64`` -with ``linux-aarch64``; for Windows, use ``win-64``. Only the current CUDA -major version is built on ``main``; wheels for the prior CUDA major are -published from the corresponding backport branch. +with ``linux-aarch64``; for Windows, use ``win-64``. To use the CUDA 12 line, +replace ``cuda13`` with ``cuda12`` in both commands. Both supported CUDA major +lines are published by CI from ``main``. Installing from Source ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/cuda_python/docs/environment-docs.yml b/cuda_python/docs/environment-docs.yml index 3152f0a3a93..a82fd02aa5e 100644 --- a/cuda_python/docs/environment-docs.yml +++ b/cuda_python/docs/environment-docs.yml @@ -19,6 +19,8 @@ dependencies: - sphinx-copybutton - myst-nb - enum_tools + # cuda_bindings_12/docs/source/conf.py uses the Furo theme. + - furo - sphinx-toolbox - pyclibrary - pip: diff --git a/toolshed/setup-docs-env.sh b/toolshed/setup-docs-env.sh index 9acbaa8e391..73afbbf06f9 100755 --- a/toolshed/setup-docs-env.sh +++ b/toolshed/setup-docs-env.sh @@ -51,6 +51,7 @@ conda create -y -n "${ENV_NAME}" \ sphinx-copybutton \ myst-nb \ enum_tools \ + furo \ sphinx-toolbox \ pyclibrary From 1b1249c158a7c202a74c473617c2b27d477499b9 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 20 Oct 2026 22:14:26 -0700 Subject: [PATCH 02/19] CI: label metapackage GPU suites as meta Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/test-wheel-linux.yml | 2 +- .github/workflows/test-wheel-windows.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-wheel-linux.yml b/.github/workflows/test-wheel-linux.yml index 8d83d975326..9eae82f8a08 100644 --- a/.github/workflows/test-wheel-linux.yml +++ b/.github/workflows/test-wheel-linux.yml @@ -138,7 +138,7 @@ jobs: [if $workplan == null or $workplan.modules.pathfinder.needs_test then "pathfinder" else empty end, if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.bindings.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "bindings" + ($row.CUDA_VER | split(".")[0]) else empty end, if $workplan == null or $workplan.modules.core.cuda_majors[$row.CUDA_VARIANT].needs_test then "core" + ($row.CUDA_VER | split(".")[0]) else empty end, - if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "python" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) + if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "meta" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) }) | map(select(.SUITES != "")) | if any(.[]; .DRIVER != "latest" and .DRIVER != "earliest" and .FLAVOR == "wsl") then "Error: custom DRIVER is not supported with FLAVOR=wsl\n" | halt_error(1) else . end diff --git a/.github/workflows/test-wheel-windows.yml b/.github/workflows/test-wheel-windows.yml index 8c6fa97caa4..e20688d4174 100644 --- a/.github/workflows/test-wheel-windows.yml +++ b/.github/workflows/test-wheel-windows.yml @@ -133,7 +133,7 @@ jobs: [if $workplan == null or $workplan.modules.pathfinder.needs_test then "pathfinder" else empty end, if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.bindings.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "bindings" + ($row.CUDA_VER | split(".")[0]) else empty end, if $workplan == null or $workplan.modules.core.cuda_majors[$row.CUDA_VARIANT].needs_test then "core" + ($row.CUDA_VER | split(".")[0]) else empty end, - if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "python" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) + if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "meta" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) }) | map(select(.SUITES != "")) | map(. + {RUNNER_DRIVER: (if .DRIVER == "latest" or .DRIVER == "earliest" then .DRIVER else "latest" end)}) From 01d209e309b1c665e41545077ac608a0d9cef830 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Oct 2026 10:23:29 -0700 Subject: [PATCH 03/19] Adapt CUDA 12 NVML tests for current CI runners Relocate the established hardware, driver, visibility and timing accommodations from the source-integration layer. Preserve their contents exactly; the FieldId correction moves with the test maintenance. Signed-off-by: Ralf W. Grosse-Kunstleve --- cuda_bindings_12/tests/nvml/test_cuda.py | 26 ++++++++++++++++++---- cuda_bindings_12/tests/nvml/test_init.py | 14 +++++++++++- cuda_bindings_12/tests/nvml/test_pynvml.py | 18 --------------- cuda_bindings_12/tests/nvml/util.py | 2 +- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/cuda_bindings_12/tests/nvml/test_cuda.py b/cuda_bindings_12/tests/nvml/test_cuda.py index d05e2634a12..aaab23e55fe 100644 --- a/cuda_bindings_12/tests/nvml/test_cuda.py +++ b/cuda_bindings_12/tests/nvml/test_cuda.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +import pytest + import cuda.bindings.driver as cuda from cuda.bindings import nvml @@ -15,10 +17,15 @@ def get_nvml_device_names(): for idx in range(num_devices): handle = nvml.device_get_handle_by_index_v2(idx) name = nvml.device_get_name(handle) - info = nvml.device_get_pci_info_v3(handle) - assert isinstance(info.bus, int) + try: + info = nvml.device_get_pci_info_v3(handle) + except nvml.NotSupportedError: + bus_id = -1 + else: + bus_id = info.bus + assert isinstance(bus_id, int) assert isinstance(name, str) - result.append({"name": name, "id": info.bus}) + result.append({"name": name, "id": bus_id}) return result @@ -54,4 +61,15 @@ def test_cuda_device_order(): cuda_devices = get_cuda_device_names() nvml_devices = get_nvml_device_names() - assert cuda_devices == nvml_devices, "CUDA and NVML device lists do not match" + for kind in ("Orin", "Thor"): + if any(kind in device["name"] for device in nvml_devices): + pytest.skip(f"Skipping test on {kind}, which has non-standard device naming") + + def compare(cuda_device, nvml_device): + return cuda_device["name"] == nvml_device["name"] and ( + nvml_device["id"] == -1 or cuda_device["id"] == nvml_device["id"] + ) + + assert len(cuda_devices) <= len(nvml_devices) + for cuda_device in cuda_devices: + assert any(compare(cuda_device, nvml_device) for nvml_device in nvml_devices) diff --git a/cuda_bindings_12/tests/nvml/test_init.py b/cuda_bindings_12/tests/nvml/test_init.py index 94b489ab45f..bcda0591bb6 100644 --- a/cuda_bindings_12/tests/nvml/test_init.py +++ b/cuda_bindings_12/tests/nvml/test_init.py @@ -6,7 +6,15 @@ import pytest -from cuda.bindings import nvml +from cuda.bindings import driver, nvml + + +def _driver_version_at_least_13_4(): + (status,) = driver.cuInit(0) + assert status == driver.CUresult.CUDA_SUCCESS + status, version = driver.cuDriverGetVersion() + assert status == driver.CUresult.CUDA_SUCCESS + return version >= 13040 def assert_nvml_is_initialized(): @@ -36,10 +44,14 @@ def test_devices_are_the_same_architecture(all_devices): @pytest.mark.skipif(sys.platform == "win32", reason="Test not supported on Windows") +@pytest.mark.thread_unsafe(reason="nvml init affects other threads") def test_init_ref_count(): """ Verifies that we can call NVML shutdown and init(2) multiple times, and that ref counting works """ + if _driver_version_at_least_13_4(): + pytest.skip("Init behavior changed in CUDA 13.4") + with pytest.raises(nvml.UninitializedError): nvml.shutdown() diff --git a/cuda_bindings_12/tests/nvml/test_pynvml.py b/cuda_bindings_12/tests/nvml/test_pynvml.py index a96b2c87575..e3ea533dd83 100644 --- a/cuda_bindings_12/tests/nvml/test_pynvml.py +++ b/cuda_bindings_12/tests/nvml/test_pynvml.py @@ -4,8 +4,6 @@ # A set of tests ported from https://github.com/gpuopenanalytics/pynvml/blob/11.5.3/pynvml/tests/test_nvml.py import os -import time - import pytest from cuda.bindings import nvml @@ -147,22 +145,6 @@ def test_device_get_power_usage(ngpus, handles): assert power_mwatts >= 0.0 -def test_device_get_total_energy_consumption(ngpus, handles): - for i in range(ngpus): - with unsupported_before(handles[i], nvml.DeviceArch.VOLTA): - energy_mjoules1 = nvml.device_get_total_energy_consumption(handles[i]) - - for j in range(10): # idle for 150 ms - time.sleep(0.015) # and check for increase every 15 ms - with unsupported_before(handles[i], nvml.DeviceArch.VOLTA): - energy_mjoules2 = nvml.device_get_total_energy_consumption(handles[i]) - assert energy_mjoules2 >= energy_mjoules1 - if energy_mjoules2 > energy_mjoules1: - break - else: - raise AssertionError("energy did not increase across 150 ms interval") - - # [Skipping] pynvml.nvmlDeviceGetGpuOperationMode # [Skipping] pynvml.nvmlDeviceGetCurrentGpuOperationMode # [Skipping] pynvml.nvmlDeviceGetPendingGpuOperationMode diff --git a/cuda_bindings_12/tests/nvml/util.py b/cuda_bindings_12/tests/nvml/util.py index 038fe58d8be..06cb1c2277a 100644 --- a/cuda_bindings_12/tests/nvml/util.py +++ b/cuda_bindings_12/tests/nvml/util.py @@ -43,5 +43,5 @@ def supports_ecc(device): def supports_nvlink(device): fields = nvml.FieldValue(1) - fields[0].field_id = nvml.FI.DEV_NVLINK_GET_STATE + fields[0].field_id = nvml.FieldId.DEV_NVLINK_GET_STATE return nvml.device_get_field_values(device, fields)[0].nvml_return == nvml.Return.SUCCESS From 59dbb3ea8601b555e238762fec775745204fe9b6 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Oct 2026 21:14:54 -0700 Subject: [PATCH 04/19] Bound cuDSS test dependencies to the supported loader ABI Signed-off-by: Ralf W. Grosse-Kunstleve --- cuda_pathfinder/pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/pyproject.toml b/cuda_pathfinder/pyproject.toml index 904463b7022..7cc17150020 100644 --- a/cuda_pathfinder/pyproject.toml +++ b/cuda_pathfinder/pyproject.toml @@ -28,6 +28,7 @@ test-ft = [ "pytest-run-parallel==0.10.0", ] # Internal organization of test dependencies. +# The cuDSS bounds match the 0.x library ABI currently supported by the loader. cu12 = [ "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl,cupti,profiler]==12.*", "cuda-toolkit[cufile]==12.*; sys_platform != 'win32'", @@ -35,7 +36,7 @@ cu12 = [ "cutensor-cu12", "nvidia-cublasmp-cu12; sys_platform != 'win32'", "nvidia-cudnn-cu12>=9,<10", - "nvidia-cudss-cu12", + "nvidia-cudss-cu12<1", "nvidia-cufftmp-cu12; sys_platform != 'win32'", "nvidia-cusolvermp-cu12; sys_platform != 'win32'", "nvidia-cusparselt-cu12", @@ -51,7 +52,7 @@ cu13 = [ "nvidia-cublasmp-cu13; sys_platform != 'win32'", "nvidia-cudla; platform_system == 'Linux' and platform_machine == 'aarch64'", "nvidia-cudnn-cu13>=9,<10", - "nvidia-cudss-cu13", + "nvidia-cudss-cu13<1", "nvidia-cufftmp-cu13; sys_platform != 'win32'", "nvidia-cusolvermp-cu13; sys_platform != 'win32'", "nvidia-cusparselt-cu13", From 1b10eae35f384691f746c0135877479d474fcc3f Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 25 Oct 2026 16:53:01 -0700 Subject: [PATCH 05/19] Align multi-major CI with main's security and loader updates Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/build-docs.yml | 6 ++++++ .github/workflows/ci-nightly.yml | 3 +++ .github/workflows/ci-pixi-source-test.yml | 10 ++++++++++ .github/workflows/coverage.yml | 5 +++++ cuda_pathfinder/pyproject.toml | 5 ++--- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index d121389e57c..514c8d35167 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -78,6 +78,12 @@ jobs: ref: ${{ github.sha }} path: .ci-control + - name: Harden pip + # The release checkout can predate this action; use the workflow revision. + uses: $/.github/actions/harden-pip + with: + python: python3 + - name: Install CI tool dependencies run: python3 -m pip install -e ./.ci-control/ci diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index 072758c561b..ebc4170ecda 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -82,6 +82,9 @@ jobs: with: fetch-depth: 1 + - name: Harden pip + uses: ./.github/actions/harden-pip + - name: Install CI tool dependencies run: python -m pip install -e ./ci diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index a6456f72d33..fd401b01b87 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -95,6 +95,11 @@ jobs: # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true + - name: Harden pip + uses: ./.github/actions/harden-pip + with: + python: python3 + - name: Install CI tool dependencies run: python3 -m pip install -e ./ci @@ -272,6 +277,11 @@ jobs: # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true + - name: Harden pip + uses: ./.github/actions/harden-pip + with: + python: python3 + - name: Install CI tool dependencies run: python3 -m pip install -e ./ci diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 91ee5fe1f58..2324b914f19 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,6 +25,11 @@ jobs: steps: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Harden pip + uses: ./.github/actions/harden-pip + with: + python: python3 + - name: Install CI tool dependencies run: python3 -m pip install -e ./ci - name: Resolve current CUDA bindings package diff --git a/cuda_pathfinder/pyproject.toml b/cuda_pathfinder/pyproject.toml index 7cc17150020..904463b7022 100644 --- a/cuda_pathfinder/pyproject.toml +++ b/cuda_pathfinder/pyproject.toml @@ -28,7 +28,6 @@ test-ft = [ "pytest-run-parallel==0.10.0", ] # Internal organization of test dependencies. -# The cuDSS bounds match the 0.x library ABI currently supported by the loader. cu12 = [ "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl,cupti,profiler]==12.*", "cuda-toolkit[cufile]==12.*; sys_platform != 'win32'", @@ -36,7 +35,7 @@ cu12 = [ "cutensor-cu12", "nvidia-cublasmp-cu12; sys_platform != 'win32'", "nvidia-cudnn-cu12>=9,<10", - "nvidia-cudss-cu12<1", + "nvidia-cudss-cu12", "nvidia-cufftmp-cu12; sys_platform != 'win32'", "nvidia-cusolvermp-cu12; sys_platform != 'win32'", "nvidia-cusparselt-cu12", @@ -52,7 +51,7 @@ cu13 = [ "nvidia-cublasmp-cu13; sys_platform != 'win32'", "nvidia-cudla; platform_system == 'Linux' and platform_machine == 'aarch64'", "nvidia-cudnn-cu13>=9,<10", - "nvidia-cudss-cu13<1", + "nvidia-cudss-cu13", "nvidia-cufftmp-cu13; sys_platform != 'win32'", "nvidia-cusolvermp-cu13; sys_platform != 'win32'", "nvidia-cusparselt-cu13", From dacec0eee5a05721b1d25d15f4c7c42741dd3573 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 25 Oct 2026 16:55:06 -0700 Subject: [PATCH 06/19] Use the checked-out docs control plane for pip hardening Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/build-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 514c8d35167..75494e614c5 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -80,7 +80,7 @@ jobs: - name: Harden pip # The release checkout can predate this action; use the workflow revision. - uses: $/.github/actions/harden-pip + uses: ./.ci-control/.github/actions/harden-pip with: python: python3 From eb417f6e17ab6b9656b663c79fdc8673d031aa21 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 25 Oct 2026 17:15:51 -0700 Subject: [PATCH 07/19] Build CUDA 13 documentation against the checkout's bindings Signed-off-by: Ralf W. Grosse-Kunstleve --- cuda_bindings_13/pixi.lock | 1092 ++++++++++++++++++++++++++++++++---- cuda_bindings_13/pixi.toml | 3 +- 2 files changed, 997 insertions(+), 98 deletions(-) diff --git a/cuda_bindings_13/pixi.lock b/cuda_bindings_13/pixi.lock index 428fa5472e2..aa9b9bd1c80 100644 --- a/cuda_bindings_13/pixi.lock +++ b/cuda_bindings_13/pixi.lock @@ -2027,9 +2027,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py312he9c40d5_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/charset-normalizer-3.5.2-h1114479_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-bindings-13.2.0-py312hf79963d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-13.4.92-hd2095e1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-13.4.92-h69a702a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-impl-13.4.92-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-13.4.92-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.2.9-py312h68e6be4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.22-py312h80505a6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-h7cc23a3_1.conda @@ -2101,7 +2102,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.15-py312hd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-pathfinder-1.8.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-nvvm-dev_linux-64-13.4.92-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.4-hfacf21a_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dict2css-0.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda @@ -2194,15 +2195,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.1-pyh5ded981_0.conda + - conda_source: cuda-bindings[82bbe769] @ . + - conda_source: cuda-pathfinder[e154e34f] @ ../cuda_pathfinder - pypi: https://files.pythonhosted.org/packages/8c/79/017fab2f7167a9a9795665f894d04f77aafceca80821b51589bb4b23ff5c/nvidia_sphinx_theme-0.0.9.post1-py3-none-any.whl linux-aarch64: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/backports.zstd-1.7.0-py312h22d1088_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py312h41c1d46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_10.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-bindings-13.2.0-py312hdc0efb6_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvrtc-13.4.92-hae6cbe8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-13.4.92-he9431aa_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-impl-13.4.92-hbe86820_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-tools-13.4.92-hbe86820_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cython-3.2.9-py312hbda70bc_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/debugpy-1.8.22-py312ha0853ce_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h5bc82ec_1.conda @@ -2276,7 +2280,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.15-py312hd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-pathfinder-1.8.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-nvvm-dev_linux-aarch64-13.4.92-h579c4fd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.4-hfacf21a_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dict2css-0.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda @@ -2369,6 +2373,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.1-pyh5ded981_0.conda + - conda_source: cuda-bindings[cc4fc688] @ . + - conda_source: cuda-pathfinder[85dee785] @ ../cuda_pathfinder - pypi: https://files.pythonhosted.org/packages/8c/79/017fab2f7167a9a9795665f894d04f77aafceca80821b51589bb4b23ff5c/nvidia_sphinx_theme-0.0.9.post1-py3-none-any.whl win-64: - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_3.conda @@ -2388,7 +2394,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.15-py312hd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-pathfinder-1.8.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-nvvm-dev_win-64-13.4.92-h57928b3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.4-hfacf21a_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dict2css-0.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda @@ -2485,9 +2491,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py312ha763cb9_4.conda - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_10.conda - conda: https://conda.anaconda.org/conda-forge/win-64/charset-normalizer-3.5.2-h308a848_0.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-bindings-13.2.0-py312hc128f0a_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvrtc-13.4.92-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-13.4.92-h719f0c7_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-impl-13.4.92-hfd05255_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-tools-13.4.92-hfd05255_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.2.9-py312hd245ac3_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/debugpy-1.8.22-py312ha1a9051_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/icu-78.3-h5112557_2.conda @@ -2538,6 +2545,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda - conda: https://conda.anaconda.org/conda-forge/win-64/zeromq-4.3.5-h3a581c9_12.conda - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_7.conda + - conda_source: cuda-bindings[cf1118df] @ . + - conda_source: cuda-pathfinder[00a1437c] @ ../cuda_pathfinder - pypi: https://files.pythonhosted.org/packages/8c/79/017fab2f7167a9a9795665f894d04f77aafceca80821b51589bb4b23ff5c/nvidia_sphinx_theme-0.0.9.post1-py3-none-any.whl packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda @@ -2614,6 +2623,18 @@ packages: run_exports: {} size: 3713752 timestamp: 1784214522814 +- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.46.1-default_hfdba357_103.conda + sha256: 98f9ddc6dc5d56a824b7eaea5bab6ad4bb47642288fc70d6b1b4024ac39d5595 + md5: e86f9dc615d7533c5be8b15b3a1dee8d + depends: + - ld_impl_linux-64 2.46.1 default_hbd61a6d_103 + - sysroot_linux-64 + - zstd >=1.5.7,<1.6.0a0 + license: GPL-3.0-only + license_family: GPL + run_exports: {} + size: 3706604 + timestamp: 1791565481839 - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.46.1-default_h4852527_102.conda sha256: 08d7238663fc408ba2ab60b02fa3d06a7ca9d872962e03e90c7e0fdecb7ed1d0 md5: 32fd07abe84eb14f17c7f5cc6fa8df82 @@ -2624,6 +2645,16 @@ packages: run_exports: {} size: 36337 timestamp: 1784214551894 +- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.46.1-default_h4852527_103.conda + sha256: 606a42c754752fb905fe2012d52ff370d47b5b6adefd5f7befc4ec30ce758f23 + md5: ca26f0a4f8d04fd83147af557fbd932c + depends: + - binutils_impl_linux-64 2.46.1 default_hfdba357_103 + license: GPL-3.0-only + license_family: GPL + run_exports: {} + size: 36335 + timestamp: 1791565508736 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h505cf86_4.conda sha256: 61b78574f002390b6a7fc79834fc344beaab09550068a51100eea5a485dac741 md5: 746aa619a1bcaf4da541101179d7c60e @@ -2764,31 +2795,6 @@ packages: run_exports: {} size: 331601 timestamp: 1789746783338 -- conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-bindings-13.2.0-py312hf79963d_1.conda - sha256: 749c0e2e664f76833a24a7a4d970a643888ca582fba1c46ca1b7c01b245dc99d - md5: 13d8b143b3513c95a1d3aec4e65a9529 - depends: - - __glibc >=2.17,<3.0.a0 - - cuda-nvrtc >=13,<14.0a0 - - cuda-nvvm-impl >=13,<14.0a0 - - cuda-pathfinder >=1.1.0,<2 - - cuda-version >=13,<14.0a0 - - libcufile >=1,<2.0a0 - - libgcc >=14 - - libnvfatbin - - libnvjitlink >=13.0,<14.0a0 - - libstdcxx >=14 - - python >=3.12,<3.13.0a0 - - python_abi 3.12.* *_cp312 - constrains: - - cuda-python >=13.2.0,<13.3.0a0 - - cuda-cudart >=13,<14.0a0 - license: LicenseRef-NVIDIA-SOFTWARE-LICENSE - purls: - - pkg:pypi/cuda-bindings?source=hash-mapping - run_exports: {} - size: 4143685 - timestamp: 1779249651391 - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-12.9.79-h5888daf_0.conda sha256: 57d1294ecfaf9dc8cdb5fc4be3e63ebc7614538bddb5de53cfd9b1b7de43aed5 md5: cb15315d19b58bd9cd424084e58ad081 @@ -2817,6 +2823,19 @@ packages: run_exports: {} size: 24234 timestamp: 1789613674738 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-13.4.92-hd2095e1_1.conda + sha256: 2672a4c726ae152cbd011533a3092f601f03314073ba65874d34ceb6b51a2d61 + md5: 3042de847b53d8a818d5be7380f2b3d0 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-cudart_linux-64 13.4.92 h9e77f9f_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 24261 + timestamp: 1791918060137 - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-dev-12.9.79-h5888daf_0.conda sha256: 04d8235cb3cb3510c0492c3515a9d1a6053b50ef39be42b60cafb05044b5f4c6 md5: ba38a7c3b4c14625de45784b773f0c71 @@ -2853,6 +2872,23 @@ packages: - cuda-cudart >=13.4.92,<14.0a0 size: 24719 timestamp: 1789613691099 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-dev-13.4.92-hd2095e1_1.conda + sha256: 66c42f44f3ed0c3a5808e8b01c58878fc6f320b63d7bdc446a965556888dba0d + md5: 456e334d56cfae38659da009f8dcdb15 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-cudart 13.4.92 hd2095e1_1 + - cuda-cudart-dev_linux-64 13.4.92 h9e77f9f_1 + - cuda-cudart-static 13.4.92 hd2095e1_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=13.4.92,<14.0a0 + size: 24799 + timestamp: 1791918074095 - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-static-12.9.79-h5888daf_0.conda sha256: 6261e1d9af80e1ec308e3e5e2ff825d189ef922d24093beaf6efca12e67ce060 md5: d3c4ac48f4967f09dd910d9c15d40c81 @@ -2881,6 +2917,19 @@ packages: run_exports: {} size: 24203 timestamp: 1789613683675 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-static-13.4.92-hd2095e1_1.conda + sha256: c9733c366e0bf39aba805e4a1af73864ee1c8aa32636d78649ab5ed15a702a3e + md5: 0cbec9120f1ba047ff3fe4af49fcea2b + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-cudart-static_linux-64 13.4.92 h9e77f9f_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 24189 + timestamp: 1791918068720 - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-12.9.86-hecca717_1.conda sha256: 68f81268c25befa9b70dc49af469ab0eb131960e3700b9a4edb46a32da343a28 md5: 53f0062e2243b26e43ddac0b5267c6a3 @@ -2907,6 +2956,18 @@ packages: run_exports: {} size: 40891762 timestamp: 1789606732241 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-13.4.92-hd2095e1_1.conda + sha256: 57319804ae25e7912180761325ca7ae016c8d6b2e4bc8435ae32545ecc744d6d + md5: f851f3ec1da56007ac2a527c9c47bb75 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 40861730 + timestamp: 1791919218242 - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-dev-12.9.86-hecca717_1.conda sha256: ae620051c16eabf7720a47c5115634d64f7703d32124555ad0afccfd4b8d7cf4 md5: 0d28090f4e63410e20397c7975612837 @@ -2941,6 +3002,23 @@ packages: - cuda-nvrtc >=13.4.92,<14.0a0 size: 39261 timestamp: 1789606830146 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-dev-13.4.92-hd2095e1_1.conda + sha256: 219e74a39c7cf28ece1812a464b9678ee03493a137f725846321d7558607b72b + md5: 4afc933b4cd0164a27a95996037e6142 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-nvrtc 13.4.92 hd2095e1_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + constrains: + - cuda-nvrtc-static >=13.4.92 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-nvrtc >=13.4.92,<14.0a0 + size: 39135 + timestamp: 1791919341732 - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-12.9.86-h69a702a_6.conda sha256: 5c70d91e6d30eb6000ea036558a20fd0b1bc13cdd2c04fd5dbf94d9caa0a7fbc md5: 704956f67e44ddf046565ead01f9efcd @@ -2965,6 +3043,18 @@ packages: run_exports: {} size: 26192 timestamp: 1789628110041 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-13.4.92-h69a702a_1.conda + sha256: b56e84b0c5ff2a24bbcf80e10adf670060b18297a4768c377ad5141a6994816c + md5: 333d434b7590b7da177f92c195816127 + depends: + - cuda-nvvm-dev_linux-64 13.4.92.* + - cuda-nvvm-impl 13.4.92.* + - cuda-nvvm-tools 13.4.92.* + license: LicenseRef-NVIDIA-End-User-License-Agreement + purls: [] + run_exports: {} + size: 26278 + timestamp: 1792180995966 - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-impl-12.9.86-h4bc722e_2.conda sha256: f4d34556174e4faa9d374ba2244707082870e1bbc1bb441ad3d9d2cea37da6af md5: 82125dd3c0c4aa009faa00e2829b93d8 @@ -4819,6 +4909,19 @@ packages: - libpython >=3.12,<4.0a0 size: 8773616 timestamp: 1791331736500 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpython-3.12.15-ha57cdbe_2_cpython.conda + build_number: 2 + sha256: 37017ac4a784c50f1fc73c7b0eb090c7f29f4541c9014c4b4e10daa275488fdd + md5: fe256863f652549334a81a8e49fdf097 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + license: Python-2.0 + run_exports: + weak: + - libpython >=3.12,<4.0a0 + size: 8775924 + timestamp: 1791911120563 - conda: https://conda.anaconda.org/conda-forge/linux-64/libpython-3.14.8-hdc7f604_101_cp314.conda build_number: 101 sha256: 3dc27daa3470f9b6f863942d99db623d79204ea478955ea73e97d3519cae2ab5 @@ -5007,6 +5110,17 @@ packages: run_exports: {} size: 572864 timestamp: 1790777898360 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-262.1-h26e0ef7_0.conda + sha256: fc930c169a0844dcb1f3084032d3f4e53798b2f48d4c7f4a151a87012833008a + md5: a6bb6ea85431d21bebdf7184517524ca + depends: + - __glibc >=2.17,<3.0.a0 + - libcap >=2.78,<2.79.0a0 + - libgcc >=15 + license: LGPL-2.1-or-later + run_exports: {} + size: 574718 + timestamp: 1792224216335 - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda sha256: 10e125da82ca93e09191e66e5a94d566b2cf8d4024e2a0db3a9114297447e0d9 md5: 0907d876f460ebc941ae590338b6102f @@ -5040,6 +5154,17 @@ packages: run_exports: {} size: 184629 timestamp: 1790777902394 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-262.1-h26e0ef7_0.conda + sha256: 63bc48418ed3be6166c27f294504153bf3da8579aa5d565ae4fee8bdd1682e54 + md5: b7e3531ad0f828ee27f5731fcb9ebdc3 + depends: + - __glibc >=2.17,<3.0.a0 + - libcap >=2.78,<2.79.0a0 + - libgcc >=15 + license: LGPL-2.1-or-later + run_exports: {} + size: 184945 + timestamp: 1792224219990 - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda sha256: 71c8b9d5c72473752a0bb6e91b01dd209a03916cb71f36cc6a564e3a2a132d7a md5: e179a69edd30d75c0144d7a380b88f28 @@ -5789,6 +5914,39 @@ packages: - python size: 23058586 timestamp: 1791331773684 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.15-h5f976f7_2_cpython.conda + build_number: 2 + sha256: f8a38c33f627c68e35d02cc5a11eff25eadb853791ac40bf9cc569315d25bc54 + md5: 13cef25ee4055b1fec19d35d20aadda2 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.8.5,<3.0a0 + - libffi >=3.7.0,<3.8.0a0 + - libgcc >=15 + - liblzma >=5.8.3,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libpython 3.12.15 ha57cdbe_2_cpython + - libsqlite >=3.54.0,<4.0a0 + - libuuid >=2.42.4,<3.0a0 + - libxcrypt >=4.4.38 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.9,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + run_exports: + weak: + - python_abi 3.12.* *_cp312 + noarch: + - python + size: 23065587 + timestamp: 1791911147011 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.8-hcd007b5_101_cp314.conda build_number: 101 sha256: e22f6a79d290935b2c854d325e260f70f364c7cc7ec0bc8308ded4f2f1eef7e6 @@ -6836,6 +6994,18 @@ packages: run_exports: {} size: 4677171 timestamp: 1784214549910 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.46.1-default_h5f4c503_103.conda + sha256: 1827893f9d6aa13794196b1820b8003bfff0105774a323a61026a16cec6dc66d + md5: 1ebaa45e5556156b3c7bf5bd5c527634 + depends: + - ld_impl_linux-aarch64 2.46.1 default_h1979696_103 + - sysroot_linux-aarch64 + - zstd >=1.5.7,<1.6.0a0 + license: GPL-3.0-only + license_family: GPL + run_exports: {} + size: 4911258 + timestamp: 1791565579362 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_linux-aarch64-2.46.1-default_hf1166c9_102.conda sha256: d41099a3fe2809a3ab3e4c718ecff4d5f8879e7949f3c8e8efa97fa06a90248c md5: 9a340123cb7217eae51c5cae24484631 @@ -6846,6 +7016,16 @@ packages: run_exports: {} size: 36196 timestamp: 1784214578949 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_linux-aarch64-2.46.1-default_hf1166c9_103.conda + sha256: 60e63ac488aac474f8a22ea465d317daa02fccd039cca75e288bd0fc37e8745a + md5: 9074b4a634a2be79ee49cd85b54a7f34 + depends: + - binutils_impl_linux-aarch64 2.46.1 default_h5f4c503_103 + license: GPL-3.0-only + license_family: GPL + run_exports: {} + size: 36474 + timestamp: 1791565619784 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-1.2.0-h52fc18c_4.conda sha256: 73cccc8488da976cbdf32e3b5c6182aef6d77c9dfabd0e5f5fa2ca6e03d51921 md5: 207d4f45f94f6d755a7fe1455e3148d7 @@ -6963,31 +7143,6 @@ packages: run_exports: {} size: 350096 timestamp: 1789746782725 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-bindings-13.2.0-py312hdc0efb6_1.conda - sha256: b8784c43ccd7c61c3944b48e7751e454e8c4b9ae50cabf42696e432b2e5b6b3b - md5: c7560ec15413c9b14e46d26c2ce94fb3 - depends: - - cuda-nvrtc >=13,<14.0a0 - - cuda-nvvm-impl >=13,<14.0a0 - - cuda-pathfinder >=1.1.0,<2 - - cuda-version >=13,<14.0a0 - - libcufile >=1,<2.0a0 - - libgcc >=14 - - libnvfatbin - - libnvjitlink >=13.0,<14.0a0 - - libstdcxx >=14 - - python >=3.12,<3.13.0a0 - - python >=3.12,<3.13.0a0 *_cpython - - python_abi 3.12.* *_cp312 - constrains: - - cuda-python >=13.2.0,<13.3.0a0 - - cuda-cudart >=13,<14.0a0 - license: LicenseRef-NVIDIA-SOFTWARE-LICENSE - purls: - - pkg:pypi/cuda-bindings?source=hash-mapping - run_exports: {} - size: 3866781 - timestamp: 1779249873318 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-12.9.79-h3ae8b8a_0.conda sha256: 3d6699fc27ffabf28a9d359b48e7b88437e4d945844718a58608627998db5d1b md5: df78e19e5fe656631d1470aa0fcf6ced @@ -7016,6 +7171,19 @@ packages: run_exports: {} size: 24420 timestamp: 1789613707699 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-13.4.92-hae6cbe8_1.conda + sha256: 770b6d73c8f2b20eddd8e670079b93245d58fb613c6a377bc612be221c41c3de + md5: b104d84fca7f8253c40aa5120906e050 + depends: + - arm-variant * sbsa + - cuda-cudart_linux-aarch64 13.4.92 hae6cbe8_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 24455 + timestamp: 1791918095186 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-dev-12.9.79-h3ae8b8a_0.conda sha256: d70f85411992e03494f2fe94a9852d79f366a92f40ba791611eda5551044afe9 md5: d58cc487273764a11637456c06399ff0 @@ -7052,6 +7220,23 @@ packages: - cuda-cudart >=13.4.92,<14.0a0 size: 24906 timestamp: 1789613723829 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-dev-13.4.92-hae6cbe8_1.conda + sha256: 77beb9c91a07a21147541d229c8fce9b69513e8e0c1049bbdfb0c1c36d837533 + md5: 259c69ef83a5920548a789672ac479c7 + depends: + - arm-variant * sbsa + - cuda-cudart 13.4.92 hae6cbe8_1 + - cuda-cudart-dev_linux-aarch64 13.4.92 hae6cbe8_1 + - cuda-cudart-static 13.4.92 hae6cbe8_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=13.4.92,<14.0a0 + size: 24850 + timestamp: 1791918109321 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-static-12.9.79-h3ae8b8a_0.conda sha256: dac33edcebbf557563a41521f67961039186efbc276903d937b32243ef3be937 md5: 365adcddf99b81eb323698fda31d507c @@ -7080,6 +7265,19 @@ packages: run_exports: {} size: 24336 timestamp: 1789613715481 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-static-13.4.92-hae6cbe8_1.conda + sha256: d40d5ba6da848b01c1595cda45505651069c98669fde4725b8c4eb87d66b50e3 + md5: c02b4368963fd077341a2f3f48563400 + depends: + - arm-variant * sbsa + - cuda-cudart-static_linux-aarch64 13.4.92 hae6cbe8_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 24414 + timestamp: 1791918102674 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvrtc-12.9.86-h8f3c8d4_1.conda sha256: e7f8d835d7bf993dcad9fba6db5af89c35b2b4f0282799b729bf6ad2c3bd896d md5: 48187c09673a42f9930764e8170b8787 @@ -7106,6 +7304,18 @@ packages: run_exports: {} size: 39026820 timestamp: 1789606765991 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvrtc-13.4.92-hae6cbe8_1.conda + sha256: c43853c59e2b6894489aae23a552e313e37687b3aca709e9d5f8ddb10b8e3554 + md5: d79160de33f2098808a6069a885b72ac + depends: + - arm-variant * sbsa + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 39027767 + timestamp: 1791919196421 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvrtc-dev-12.9.86-h8f3c8d4_1.conda sha256: b1d1a74cbbdcf46c4ee737279df3220eb7a29393999bc96b3c1398f7de78c912 md5: 2346ee558cbfb7b857c8353ffc2553fa @@ -7142,6 +7352,24 @@ packages: - cuda-nvrtc >=13.4.92,<14.0a0 size: 39133 timestamp: 1789606900425 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvrtc-dev-13.4.92-hae6cbe8_1.conda + sha256: 6eb1b25932421a1f2448088e41ae99cd0707b9745f2c85d0c0e4c1469da96f38 + md5: c796f4e54351b72c9ebd277e2b30d97c + depends: + - arm-variant * sbsa + - cuda-nvrtc 13.4.92 hae6cbe8_1 + - cuda-version >=13.4,<13.5.0a0 + - libgcc >=15 + - libstdcxx >=15 + constrains: + - arm-variant * sbsa + - cuda-nvrtc-static >=13.4.92 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-nvrtc >=13.4.92,<14.0a0 + size: 39155 + timestamp: 1791919300033 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-12.9.86-he9431aa_106.conda sha256: 97bf1688e3847090d1c4193c39ca575a67e2183d0c20ddf8bcedc0f9d9528bbc md5: 8ace2a8121a5f733a902822290aae11c @@ -7166,6 +7394,18 @@ packages: run_exports: {} size: 26203 timestamp: 1789628130654 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-13.4.92-he9431aa_1.conda + sha256: b835df7c790cc0d60be31a870348173dca3ef6d73c7c8d8a679fa062ab7b8764 + md5: 0d49e36b65fd93fcfcba7614ed92dafb + depends: + - cuda-nvvm-dev_linux-aarch64 13.4.92.* + - cuda-nvvm-impl 13.4.92.* + - cuda-nvvm-tools 13.4.92.* + license: LicenseRef-NVIDIA-End-User-License-Agreement + purls: [] + run_exports: {} + size: 26382 + timestamp: 1792181032938 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-impl-12.9.86-h7b14b0b_2.conda sha256: 100accfc6f608004ddef4b9004ee5179eddbac19e7d5c4c7bd5e6e8b71bd7c5d md5: 8e9fceb7b677be7107cc9c20f8d71d86 @@ -8848,6 +9088,18 @@ packages: - libprotobuf >=7.35.1,<7.35.2.0a0 size: 3844240 timestamp: 1787657628222 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpython-3.12.15-h3cfa5a6_2_cpython.conda + build_number: 2 + sha256: f648ca90465a83e36e86e35f3fdb94b5831b0d6730f3ab0e74e795249c21d01b + md5: c52923e959d965a484ea30fc977055be + depends: + - libgcc >=15 + license: Python-2.0 + run_exports: + weak: + - libpython >=3.12,<4.0a0 + size: 8229775 + timestamp: 1791911648328 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpython-3.12.15-hc3dd739_1_cpython.conda build_number: 1 sha256: f9dab218e56d5eb40f9e0bf4b71ed08e62ac6af5ea8440bc57fcbf399f8afe23 @@ -9040,6 +9292,16 @@ packages: run_exports: {} size: 592152 timestamp: 1790777808830 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsystemd0-262.1-hd1ea486_0.conda + sha256: aea93da32087cc4e1f46bd0596f487ad92e1dbab282dec0d739a7f406cb42df6 + md5: 5f1e0ce7fe60051e614f505b00055cb9 + depends: + - libcap >=2.78,<2.79.0a0 + - libgcc >=15 + license: LGPL-2.1-or-later + run_exports: {} + size: 593299 + timestamp: 1792224110959 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.2-h45f9f85_1.conda sha256: fa6daf2301dee912def3e74344fae792a8fc2bbbf7880dedee0e93ee8fb98fc5 md5: c6f35f8f9695623b9055341bc280a642 @@ -9071,6 +9333,16 @@ packages: run_exports: {} size: 195674 timestamp: 1790777812289 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libudev1-262.1-hd1ea486_0.conda + sha256: ed708af321e72984beb4cbf2c9127b6d0a0b2e484d4cca670f0ae02ceee76a83 + md5: 7d5081ffee4a31823c3af8dc2cb1cf24 + depends: + - libcap >=2.78,<2.79.0a0 + - libgcc >=15 + license: LGPL-2.1-or-later + run_exports: {} + size: 196616 + timestamp: 1792224114009 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libunwind-1.8.3-h6470e1d_0.conda sha256: 86c013d522975b76e16a74341bfcb22f6ec2e9b8b87ec3e15380f46c435eaa7b md5: 5d8191a950e492a06dc29b491dd5f7c5 @@ -9712,6 +9984,38 @@ packages: - python size: 22433184 timestamp: 1791331900447 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.12.15-h94ad73b_2_cpython.conda + build_number: 2 + sha256: bb5313eaffc0b1f0e8d8d170604389b46dc5fd13cec5593a2228e2fdf24e86db + md5: f0ae8219e89d92aaea1a7a3e25075e46 + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-aarch64 >=2.36.1 + - libexpat >=2.8.5,<3.0a0 + - libffi >=3.7.0,<3.8.0a0 + - libgcc >=15 + - liblzma >=5.8.3,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libpython 3.12.15 h3cfa5a6_2_cpython + - libsqlite >=3.54.0,<4.0a0 + - libuuid >=2.42.4,<3.0a0 + - libxcrypt >=4.4.38 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.9,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + run_exports: + weak: + - python_abi 3.12.* *_cp312 + noarch: + - python + size: 22394723 + timestamp: 1791911676748 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.8-hbec3b18_101_cp314.conda build_number: 101 sha256: b88a76c72f76e7ad9c46068e3c9467a363425a709ae9d7cdf8c8a7b0f30220d4 @@ -10808,6 +11112,24 @@ packages: run_exports: {} size: 131396 timestamp: 1792483552251 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-h4c7d964_0.conda + sha256: f1d280d2618de987204102090e83733089c092dc2dd45686fd3dcbe809034f6a + md5: ea9dc39dcd2815202749c1e5bc2a8973 + depends: + - __win + license: ISC + run_exports: {} + size: 130423 + timestamp: 1792772460189 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-hbd8a1cb_0.conda + sha256: 95619b9c1184be7175392eeb0ee7eeb5ccf25d280951f4225f2d62e725790be3 + md5: 3fd02989038a1e1cee627c14c2d73f29 + depends: + - __unix + license: ISC + run_exports: {} + size: 130057 + timestamp: 1792772446739 - conda: https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.14.4-pyha770c72_0.conda sha256: cca3a26282a5bc37a10afb1aa2006a21c45033cbc4ff012f9501f56f2a115c12 md5: 13bdbb9b693b29134c56a9a00c23de41 @@ -11051,6 +11373,20 @@ packages: - cuda-cudart >=13.4.92,<14.0a0 size: 416061 timestamp: 1789613678504 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_linux-64-13.4.92-h9e77f9f_1.conda + sha256: b57e47ceaa7a3ddfc578f03c1856cd02008f95bf633332a8e53bf9287a8702c7 + md5: 5f9ffe3ad903033e93e98d78f16378be + depends: + - cuda-cccl_linux-64 + - cuda-cudart-static_linux-64 + - cuda-cudart_linux-64 + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=13.4.92,<14.0a0 + size: 414750 + timestamp: 1791918064480 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_linux-aarch64-12.9.79-h3ae8b8a_0.conda sha256: ad64a1ecfc933172dbc6407d71b1abb78dc7ffcd5cc871baee238350307a7c0c md5: 60e07c05a51d5549bec1e7ee38849feb @@ -11083,6 +11419,21 @@ packages: - cuda-cudart >=13.4.92,<14.0a0 size: 415739 timestamp: 1789613711959 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_linux-aarch64-13.4.92-hae6cbe8_1.conda + sha256: 12ec82791e888381c91313d665ecc46df601341636e9b058cf3cabb03c5f6096 + md5: 36d5fad84dbeb187005f085d9daeb8c4 + depends: + - arm-variant * sbsa + - cuda-cccl_linux-aarch64 + - cuda-cudart-static_linux-aarch64 + - cuda-cudart_linux-aarch64 + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=13.4.92,<14.0a0 + size: 414595 + timestamp: 1791918098639 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_win-64-12.9.79-he0c23c2_0.conda sha256: e022d36a333420130faf6473c49f8dab54bf976cf320577ffb06db0a0797b734 md5: 3c3e2f6b5455783fd332a072d632ea78 @@ -11111,9 +11462,21 @@ packages: run_exports: {} size: 1668588 timestamp: 1789613696484 -- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-64-12.9.79-h3f2d84a_0.conda - sha256: d435f8a19b59b52ce460ee3a6bfd877288a0d1d645119a6ba60f1c3627dc5032 - md5: b87bf315d81218dd63eb46cc1eaef775 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_win-64-13.4.92-hac47afa_1.conda + sha256: 5fe763d0bfd19a7c122cae5eee218f7a8276763417b7116250bcfd161f9f7595 + md5: cbc8db11f210a9af642c8a82fc3d0efa + depends: + - cuda-cccl_win-64 + - cuda-cudart-static_win-64 + - cuda-cudart_win-64 + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 1672429 + timestamp: 1791918060378 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-64-12.9.79-h3f2d84a_0.conda + sha256: d435f8a19b59b52ce460ee3a6bfd877288a0d1d645119a6ba60f1c3627dc5032 + md5: b87bf315d81218dd63eb46cc1eaef775 depends: - cuda-version >=12.9,<12.10.0a0 license: LicenseRef-NVIDIA-End-User-License-Agreement @@ -11131,6 +11494,15 @@ packages: run_exports: {} size: 1249118 timestamp: 1789613660480 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-64-13.4.92-h9e77f9f_1.conda + sha256: e51d1a571b02b1a427d16e2dc0c135a682900007e26d9d717e79bab0c58e4571 + md5: e6bd43601eb40f4330a934dc77f7d62c + depends: + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 1244417 + timestamp: 1791918050319 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-aarch64-12.9.79-h3ae8b8a_0.conda sha256: d4be038bad9abf0eac1e88dc57c8db6a469db8eb5d7c281085dfbb018ef84212 md5: 52498fedeb43bbd4c45f84a0fb722d21 @@ -11153,6 +11525,16 @@ packages: run_exports: {} size: 1245773 timestamp: 1789613695146 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-aarch64-13.4.92-hae6cbe8_1.conda + sha256: 9b7dff56b77ac18628f75cccb4dc7b940ff790e65f1def546facd73ffa726f5e + md5: 148d6b955ea3e7ec16d3e0e46de5c8f1 + depends: + - arm-variant * sbsa + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 1242539 + timestamp: 1791918083843 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_win-64-12.9.79-he0c23c2_0.conda sha256: 6a3410cd7ce07955cb705801055ef129ebee1cd6390c6fe9e5f607b67c3dba36 md5: 0dd152a1493d90356037604a865f050f @@ -11173,6 +11555,15 @@ packages: run_exports: {} size: 82544 timestamp: 1789613678949 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_win-64-13.4.92-hac47afa_1.conda + sha256: aa034a686ab953d19c462b91512ca75dc6c765fb7251357393103f7dabff9eb0 + md5: 8dd7ed65a32572fe4718ce7b6884a8cf + depends: + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 82491 + timestamp: 1791918049017 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-64-12.9.79-h3f2d84a_0.conda sha256: 6cde0ace2b995b49d0db2eefb7bc30bf00ffc06bb98ef7113632dec8f8907475 md5: 64508631775fbbf9eca83c84b1df0cae @@ -11193,6 +11584,15 @@ packages: run_exports: {} size: 209905 timestamp: 1789613664868 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-64-13.4.92-h9e77f9f_1.conda + sha256: 33ff49906d42aa43847fd9b7fb139c064df3eb40dd10c85e0a84d224658d0bfc + md5: 49b13a38cd090122c59c10c77fd2a566 + depends: + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 209978 + timestamp: 1791918053765 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-aarch64-12.9.79-h3ae8b8a_0.conda sha256: 4900ff2f000a4f8a70a7bc8576469640aa6590618fa9e73c84e066e025dcb760 md5: cc2459ad427431e089d78d760cf24437 @@ -11215,6 +11615,16 @@ packages: run_exports: {} size: 223916 timestamp: 1789613700405 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-aarch64-13.4.92-hae6cbe8_1.conda + sha256: d8057012693e22e398b1089652545a338e3d577ca90f090da5bb2c62f7d72d02 + md5: 2e93fd552844f60e9fbe9d2c287be7d2 + depends: + - arm-variant * sbsa + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 223994 + timestamp: 1791918088368 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_win-64-12.9.79-he0c23c2_0.conda sha256: 6a89a53cdbcfafa0bb55abee1b58492c6a9a28e688abe04f48f0d01649c5f3e4 md5: 71c9c2ab52226f990f268164381d8494 @@ -11235,6 +11645,15 @@ packages: run_exports: {} size: 24076 timestamp: 1789613682979 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_win-64-13.4.92-hac47afa_1.conda + sha256: 6a53afca9c5db3b75d57e446ba926b3327e261da39bd637f9b996f2e257267f9 + md5: 37a74c183777ec891017fe03c1705c3e + depends: + - cuda-version >=13.4,<13.5.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 24041 + timestamp: 1791918051282 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-nvvm-dev_linux-64-12.9.86-ha770c72_2.conda sha256: 522722dcaffd133e0c7500c69dc70e21ac34d6762dcbaabfe847439f944028f0 md5: 7b386291414c7eea113d25ac28a33772 @@ -11299,20 +11718,6 @@ packages: run_exports: {} size: 33726 timestamp: 1789621799731 -- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-pathfinder-1.8.3-pyhc364b38_0.conda - sha256: 25b8f625cebe056be045bf9e484549188296b79793a340e059f13de4338939be - md5: cb2babe521da8b1acaaea1cc12a282af - depends: - - python >=3.10 - - cuda-version >=12.0,<14 - - python - license: Apache-2.0 - license_family: APACHE - purls: - - pkg:pypi/cuda-pathfinder?source=compressed-mapping - run_exports: {} - size: 53393 - timestamp: 1790912935126 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-12.9-h4f385c5_3.conda sha256: 5f5f428031933f117ff9f7fcc650e6ea1b3fef5936cf84aa24af79167513b656 md5: b6d5d7f1c171cbd228ea06b556cfa859 @@ -13117,6 +13522,13 @@ packages: run_exports: {} size: 118849 timestamp: 1784250406640 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + sha256: 2b7ca858879f183ce2dcc65b300f48a0133d5430550f35b23d80d405a0788dbf + md5: abccc3810d2b97e570dee487f2b46e38 + license: LicenseRef-Public-Domain + run_exports: {} + size: 119208 + timestamp: 1792758382821 - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.8.0-pyhd8ed1ab_0.conda sha256: c5511c190ab55168ca412f3c54592fbf677ae6250784cb72b227a7cf3f538f7d md5: 407a3d3778570bae8e8fcf554e803e43 @@ -13415,30 +13827,6 @@ packages: run_exports: {} size: 252875 timestamp: 1789746805191 -- conda: https://conda.anaconda.org/conda-forge/win-64/cuda-bindings-13.2.0-py312hc128f0a_1.conda - sha256: 31113f2c14b5e549aa59863f711890e9bf442defd7af3bd6ff192ec96e5dcdf1 - md5: a17fac259dd34ef9ee1f508933614967 - depends: - - cuda-nvrtc >=13,<14.0a0 - - cuda-nvvm-impl >=13,<14.0a0 - - cuda-pathfinder >=1.1.0,<2 - - cuda-version >=13,<14.0a0 - - libnvfatbin - - libnvjitlink >=13.0,<14.0a0 - - python >=3.12,<3.13.0a0 - - python_abi 3.12.* *_cp312 - - ucrt >=10.0.20348.0 - - vc >=14.3,<15 - - vc14_runtime >=14.44.35208 - constrains: - - cuda-python >=13.2.0,<13.3.0a0 - - cuda-cudart >=13,<14.0a0 - license: LicenseRef-NVIDIA-SOFTWARE-LICENSE - purls: - - pkg:pypi/cuda-bindings?source=hash-mapping - run_exports: {} - size: 3509245 - timestamp: 1779249639234 - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-12.9.79-he0c23c2_0.conda sha256: a30cd9adf3a70d069d4d87c5728ec16778b77071629612ca5d8513cd92d89c09 md5: 0a243d4f000a0d2f51dd94ee9132b234 @@ -13467,6 +13855,19 @@ packages: run_exports: {} size: 215067 timestamp: 1789613690715 +- conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-13.4.92-hac47afa_1.conda + sha256: 8072dd05bd1913f079725fa2b0b8f3de07203a48f295dbe25be14eb98980bc37 + md5: fbaa83a80783c23d2e8309a468772075 + depends: + - cuda-cudart_win-64 13.4.92 hac47afa_1 + - cuda-version >=13.4,<13.5.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 215004 + timestamp: 1791918056787 - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-dev-12.9.79-he0c23c2_0.conda sha256: 1ee68f0ffd37889f0fc438d4da7124054b124632e1c3bc15950b9851b002473e md5: e5bb074108bc2501f8374e80748aa181 @@ -13501,6 +13902,21 @@ packages: run_exports: {} size: 23884 timestamp: 1789613707493 +- conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-dev-13.4.92-hac47afa_1.conda + sha256: 83496a41db7ba5bcb24dd1df9577b3fa11f944c734826e02370d26b7b909e9be + md5: d445165d6611c98536982b6fd6a95ace + depends: + - cuda-cudart 13.4.92 hac47afa_1 + - cuda-cudart-dev_win-64 13.4.92 hac47afa_1 + - cuda-cudart-static 13.4.92 hac47afa_1 + - cuda-version >=13.4,<13.5.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 23941 + timestamp: 1791918067507 - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-static-12.9.79-he0c23c2_0.conda sha256: 02d3ff9ec59c7f59132ffe9398746ad9422a75706e7cad19acc6c30a5c0fc763 md5: 718879691b8119c893f587f46c734fca @@ -13529,6 +13945,19 @@ packages: run_exports: {} size: 23877 timestamp: 1789613703473 +- conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-static-13.4.92-hac47afa_1.conda + sha256: cbd7a3ddefe3f275aef653f2ce71c0177b61a549a141f6f5af10891c218e7adb + md5: b4852e2f2c5922ef5732facd6397d915 + depends: + - cuda-cudart-static_win-64 13.4.92 hac47afa_1 + - cuda-version >=13.4,<13.5.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 23939 + timestamp: 1791918065348 - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvrtc-12.9.86-hac47afa_1.conda sha256: d90ef446ac859db26286a5d39d39333c4e4cee31ba5042b5c7922bd25de531f6 md5: d68b5d96a53c80dc3dbbd8f7c3b8106d @@ -13555,6 +13984,18 @@ packages: run_exports: {} size: 36407421 timestamp: 1789606716374 +- conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvrtc-13.4.92-hac47afa_1.conda + sha256: bcf76878a22a140bf93c4ab77c9f2d3400e636e8478c4524b4cf1199629c247f + md5: d14681f66ecaae3949396f55e6a56a7b + depends: + - cuda-version >=13.4,<13.5.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 36407569 + timestamp: 1791919216363 - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvrtc-dev-12.9.86-hac47afa_1.conda sha256: 1e1c41f95d606eaf6581fccf9546ed6ee4053c42b78e11057cd6d2801b96f0e2 md5: b97225dd005cb0dcdca7911c61ca38e5 @@ -13585,6 +14026,21 @@ packages: - cuda-nvrtc >=13.4.92,<14.0a0 size: 38246 timestamp: 1789607226146 +- conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvrtc-dev-13.4.92-hac47afa_1.conda + sha256: 0e913bd798aa37746c6f3874097ab2490caf83e5650eeee27d27d76622c9f90d + md5: ba6bcf634f8c95008f82a2562074c054 + depends: + - cuda-nvrtc 13.4.92 hac47afa_1 + - cuda-version >=13.4,<13.5.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-nvrtc >=13.4.92,<14.0a0 + size: 38346 + timestamp: 1791919775736 - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-12.9.86-h719f0c7_6.conda sha256: 020a5bb67a35654f391d21b170ba763f95b7f133fec5678d69e676559dcd5653 md5: b162c7fb8b19f9102bd5f801d7f58ca2 @@ -13609,6 +14065,18 @@ packages: run_exports: {} size: 26714 timestamp: 1789628111155 +- conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-13.4.92-h719f0c7_1.conda + sha256: d421379e5437c91fbbc06fa8cdfb966faa6f8f96a3579dd80289dcafa89cf793 + md5: a8d53f64997c6374a91f750d89138753 + depends: + - cuda-nvvm-dev_win-64 13.4.92.* + - cuda-nvvm-impl 13.4.92.* + - cuda-nvvm-tools 13.4.92.* + license: LicenseRef-NVIDIA-End-User-License-Agreement + purls: [] + run_exports: {} + size: 26872 + timestamp: 1792181036038 - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-impl-12.9.86-h2466b09_2.conda sha256: 7b995ea653816b129bae6e4ee92898824a39fe82227472537bf75ac6ece7e955 md5: d8cea7bc32045bde718d0b1ceb595445 @@ -14588,6 +15056,18 @@ packages: run_exports: {} size: 47585 timestamp: 1791330099093 +- conda: https://conda.anaconda.org/conda-forge/win-64/libpython-3.12.15-hfb4101e_2_cpython.conda + build_number: 2 + sha256: 1b0a0afd12f3b4c207cd8b03ed9a5e577adb761d3b1c46a3e5ae14f149ec49b5 + md5: 436ac63cfc19db379c2277abf142bf2d + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Python-2.0 + run_exports: {} + size: 47564 + timestamp: 1791909970395 - conda: https://conda.anaconda.org/conda-forge/win-64/libpython-3.14.8-h4f90d01_101_cp314.conda build_number: 101 sha256: 04f9f3a3b9d91e47009baa4a4379ddb11af3e5402928e40e1dd4e02ca83d60f1 @@ -15272,6 +15752,34 @@ packages: - python size: 15865664 timestamp: 1791330199001 +- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.15-hb12b558_2_cpython.conda + build_number: 2 + sha256: 39d230c501c2c82a61689e5e3d2d88b84bcd85bc4f2e1429f6bc6264082ef958 + md5: cfd4a4bce81b68e249c4c0442a9c1a0d + depends: + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.8.5,<3.0a0 + - libffi >=3.7.0,<3.8.0a0 + - liblzma >=5.8.3,<6.0a0 + - libpython 3.12.15 hfb4101e_2_cpython + - libsqlite >=3.54.0,<4.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.9,<4.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + run_exports: + weak: + - python_abi 3.12.* *_cp312 + noarch: + - python + size: 15885151 + timestamp: 1791910062494 - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.8-h53f6dd8_101_cp314.conda build_number: 101 sha256: 6372598cff41f4145686a9bfa3a0399354f34fc3f813b0218a4760428a33d3db @@ -16145,6 +16653,111 @@ packages: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda - conda_source: cuda-pathfinder[a51836e4] @ ../cuda_pathfinder +- conda_source: cuda-bindings[82bbe769] @ . + variants: + c_stdlib: sysroot + c_stdlib_version: '2.28' + cuda_version: 13.4.* + python: 3.12.* + target_platform: linux-64 + depends: + - __glibc >=2.28,<3.0.a0 + - cuda-nvrtc + - cuda-nvrtc >=13.4.92,<14.0a0 + - cuda-nvvm + - cuda-pathfinder + - cuda-version + - libcufile + - libcufile >=1.19.1.55,<2.0a0 + - libgcc >=16 + - libgcc >=16 + - libnvfatbin + - libnvjitlink + - libstdcxx >=16 + - python + - python >=3.11 + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + source_depends: + cuda-pathfinder: + path: ../cuda_pathfinder + build_packages: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.46.1-default_hfdba357_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.46.1-default_h4852527_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-16.2.0-h9891192_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-16.2.0-h0ab548f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-16.2.0-h0d273dc_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-16.2.0-h23aca61_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.2.0-ha9f2e26_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-16.2.0-h3048135_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-16.2.0-he3ce08f_107.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-16.2.0-h86e191b_107.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + host_packages: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-13.4.92-hd2095e1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-dev-13.4.92-hd2095e1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-static-13.4.92-hd2095e1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-13.4.92-hd2095e1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-dev-13.4.92-hd2095e1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-13.4.92-h69a702a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-impl-13.4.92-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-13.4.92-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-profiler-api-13.4.92-h7938cbb_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.2.9-py312h68e6be4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.78-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcufile-1.19.1.55-h63c01a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcufile-dev-1.19.1.55-h393e864_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.5-hd2095e1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.7.0-h81df57d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.2.0-ha9f2e26_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpython-3.12.15-ha57cdbe_2_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.54.1-h0737f62_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-262.1-h26e0ef7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-262.1-h26e0ef7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.4-hcfc3c73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.38-h280c20c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.5-h781a0a9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.15-h5f976f7_2_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-65.0-h7b4f2e6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h1df4ec4_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.13.5-h535ca38_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cccl_linux-64-13.3.4.3.1-ha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-crt-dev_linux-64-13.4.92-ha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_linux-64-13.4.92-h9e77f9f_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-64-13.4.92-h9e77f9f_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-64-13.4.92-h9e77f9f_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-nvvm-dev_linux-64-13.4.92-ha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.4-hfacf21a_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.2.1-pyhe730653_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-10.3.4-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda + - conda_source: cuda-pathfinder[e154e34f] @ ../cuda_pathfinder - conda_source: cuda-bindings[86d21d4b] @ . variants: c_compiler: vs2022 @@ -16291,6 +16904,184 @@ packages: - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_7.conda - conda_source: cuda-pathfinder[f6abc7c0] @ ../cuda_pathfinder +- conda_source: cuda-bindings[cc4fc688] @ . + variants: + c_stdlib: sysroot + c_stdlib_version: '2.28' + cuda_version: 13.4.* + python: 3.12.* + target_platform: linux-aarch64 + depends: + - __glibc >=2.28,<3.0.a0 + - cuda-nvrtc + - cuda-nvrtc >=13.4.92,<14.0a0 + - cuda-nvvm + - cuda-pathfinder + - cuda-version + - libcufile + - libcufile >=1.19.1.55,<2.0a0 + - libgcc >=16 + - libgcc >=16 + - libnvfatbin + - libnvjitlink + - libstdcxx >=16 + - python + - python >=3.11 + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + source_depends: + cuda-pathfinder: + path: ../cuda_pathfinder + build_packages: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.46.1-default_h5f4c503_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_linux-aarch64-2.46.1-default_hf1166c9_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_impl_linux-aarch64-16.2.0-h5425ead_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_linux-aarch64-16.2.0-h25cc031_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_impl_linux-aarch64-16.2.0-h1e3c31f_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_linux-aarch64-16.2.0-h423111d_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-16.2.0-h205dda4_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-16.2.0-h8acb6b2_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsanitizer-16.2.0-h73cac2c_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-16.2.0-hef695bb_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h9d15635_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-aarch64-4.18.0-h05a177a_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-aarch64-16.2.0-hc0c2482_107.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-aarch64-16.2.0-h082e5f6_107.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-aarch64-2.28-h585391f_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + host_packages: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_10.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-dev-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-cudart-static-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvrtc-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvrtc-dev-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-13.4.92-he9431aa_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-impl-13.4.92-hbe86820_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-nvvm-tools-13.4.92-hbe86820_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cuda-profiler-api-13.4.92-h16bee8c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cython-3.2.9-py312hbda70bc_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcap-2.78-hfcc8634_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcufile-1.19.1.55-hc7dfe37_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcufile-dev-1.19.1.55-hc1d3098_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.5-h4154aff_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.7.0-hdaad0be_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-16.2.0-h205dda4_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-16.2.0-h8acb6b2_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnl-3.11.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpython-3.12.15-h3cfa5a6_2_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.54.1-hd26f1b6_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-16.2.0-hef695bb_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsystemd0-262.1-hd1ea486_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libudev1-262.1-hd1ea486_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.4-hd6fdeab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.38-h80f16a2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-h2b6f883_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.5-he6ad1d5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.12.15-h94ad73b_2_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rdma-core-65.0-h807d763_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-ha7194a6_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_hf03c496_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/uv-0.13.5-h779c035_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h9d15635_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/arm-variant-1.2.0-sbsa.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cccl_linux-aarch64-13.3.4.3.1-h579c4fd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-crt-dev_linux-aarch64-13.4.92-h579c4fd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_linux-aarch64-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-aarch64-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-aarch64-13.4.92-hae6cbe8_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-nvvm-dev_linux-aarch64-13.4.92-h579c4fd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.4-hfacf21a_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.2.1-pyhe730653_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-10.3.4-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda + - conda_source: cuda-pathfinder[85dee785] @ ../cuda_pathfinder +- conda_source: cuda-bindings[cf1118df] @ . + variants: + c_compiler: vs2022 + cuda_version: 13.4.* + cxx_compiler: vs2022 + python: 3.12.* + target_platform: win-64 + depends: + - cuda-nvrtc + - cuda-nvrtc >=13.4.92,<14.0a0 + - cuda-nvvm + - cuda-pathfinder + - cuda-version + - libnvfatbin + - libnvjitlink + - python + - python >=3.11 + - python_abi 3.12.* *_cp312 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + source_depends: + cuda-pathfinder: + path: ../cuda_pathfinder + build_packages: + - conda: https://conda.anaconda.org/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_41.conda + host_packages: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cccl_win-64-13.3.4.3.1-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-crt-dev_win-64-13.4.92-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_win-64-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_win-64-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_win-64-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-nvvm-dev_win-64-13.4.92-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.4-hfacf21a_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.2.1-pyhe730653_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-10.3.4-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_10.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-dev-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-cudart-static-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvrtc-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvrtc-dev-13.4.92-hac47afa_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-13.4.92-h719f0c7_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-impl-13.4.92-hfd05255_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-nvvm-tools-13.4.92-hfd05255_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cuda-profiler-api-13.4.92-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.2.9-py312hd245ac3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.5-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.7.0-h3d046cb_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libpython-3.12.15-hfb4101e_2_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.54.1-hf5d6505_100.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.5-hf411b9b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.15-hb12b558_2_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h967ab96_4.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/uv-0.13.5-hf7a7c96_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-ha367084_41.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36247-habf1de7_41.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_7.conda + - conda_source: cuda-pathfinder[00a1437c] @ ../cuda_pathfinder - conda_source: cuda-bindings[d813cbd1] @ . variants: c_stdlib: sysroot @@ -16395,6 +17186,76 @@ packages: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda - conda_source: cuda-pathfinder[9b57eb00] @ ../cuda_pathfinder +- conda_source: cuda-pathfinder[00a1437c] @ ../cuda_pathfinder + variants: + target_platform: noarch + depends: + - python * + - python >=3.11 + license: Apache-2.0 + host_packages: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.15-9_cp315.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.2.1-pyhe730653_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-10.3.4-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_10.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.5-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.7.0-h3d046cb_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.54.1-hf5d6505_100.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.5-hf411b9b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.15.1-h53f6dd8_100_cp315.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h967ab96_4.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/uv-0.13.5-hf7a7c96_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-ha367084_41.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36247-habf1de7_41.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_7.conda +- conda_source: cuda-pathfinder[85dee785] @ ../cuda_pathfinder + variants: + target_platform: noarch + depends: + - python * + - python >=3.11 + license: Apache-2.0 + host_packages: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_10.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20260512-pl5321hc48eb74_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.5-h4154aff_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.7.0-hdaad0be_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-16.2.0-h205dda4_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-16.2.0-h8acb6b2_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.54.1-hd26f1b6_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-16.2.0-hef695bb_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.4-hd6fdeab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-h2b6f883_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.5-he6ad1d5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.15.1-h0c7c799_100_cp315.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_hf03c496_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/uv-0.13.5-h779c035_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h9d15635_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.15-9_cp315.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.2.1-pyhe730653_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-10.3.4-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda - conda_source: cuda-pathfinder[9b57eb00] @ ../cuda_pathfinder variants: target_platform: noarch @@ -16469,6 +17330,43 @@ packages: - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda +- conda_source: cuda-pathfinder[e154e34f] @ ../cuda_pathfinder + variants: + target_platform: noarch + depends: + - python * + - python >=3.11 + license: Apache-2.0 + host_packages: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20260512-pl5321h373387f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.5-hd2095e1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.7.0-h81df57d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.2.0-ha9f2e26_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.54.1-h0737f62_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.4-hcfc3c73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.5-h781a0a9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.15.1-h6e52b48_100_cp315.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h1df4ec4_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.13.5-h535ca38_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.10.23-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.15-9_cp315.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.2.1-pyhe730653_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-10.3.4-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026e-h5d301ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vcs_versioning-2.6.0-pyh5ded981_0.conda - conda_source: cuda-pathfinder[f6abc7c0] @ ../cuda_pathfinder variants: target_platform: noarch diff --git a/cuda_bindings_13/pixi.toml b/cuda_bindings_13/pixi.toml index 0c7c58c2050..99bf5e3ca64 100644 --- a/cuda_bindings_13/pixi.toml +++ b/cuda_bindings_13/pixi.toml @@ -28,7 +28,8 @@ cuda-python-test-helpers = { path = "../cuda_python_test_helpers", editable = tr # Keep this dependency set aligned with cuda_python/docs/environment-docs.yml. [feature.docs.dependencies] -cuda-bindings = "13.2.*" +# Document the checkout's API, including modules absent from published packages. +cuda-bindings = { path = "." } python = "3.12.*" cython = ">=3.2.5,<3.3" enum_tools = "*" From 88fc236d4706e88cd85bf0b67bbfb24b7a370c33 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 14:12:09 -0700 Subject: [PATCH 08/19] Share wheel-test matrix selection across platforms Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/test-wheel-linux.yml | 76 +-------------- .github/workflows/test-wheel-windows.yml | 73 +------------- ci/tools/select_test_matrix.py | 113 ++++++++++++++++++++++ ci/tools/tests/test_select_test_matrix.py | 71 ++++++++++++++ 4 files changed, 192 insertions(+), 141 deletions(-) create mode 100644 ci/tools/select_test_matrix.py create mode 100644 ci/tools/tests/test_select_test_matrix.py diff --git a/.github/workflows/test-wheel-linux.yml b/.github/workflows/test-wheel-linux.yml index 9eae82f8a08..1effabdb8a4 100644 --- a/.github/workflows/test-wheel-linux.yml +++ b/.github/workflows/test-wheel-linux.yml @@ -91,78 +91,10 @@ jobs: # Read base matrix from YAML file for the specific architecture TEST_MATRIX=$(yq -o json ".linux[\"${MATRIX_TYPE}\"] | map(select(.ARCH == \"${ARCH}\"))" ci/test-matrix.yml) - BINDINGS_PACKAGES=$(jq -c '.package_roots' <<< "$BINDINGS_CONFIG") - CURRENT_BINDINGS_SOURCE_DIR=$(jq -r ' - .[] | select(.release_status == "current") | .package_root - ' <<< "$BINDINGS_PACKAGES") - - if [[ -z "$WORKPLAN" ]]; then - TEST_CUDA_MAJORS=$(jq -c ' - [.[].cuda_variant] | map({key: ., value: true}) | from_entries - ' <<< "$BINDINGS_PACKAGES") - PATHFINDER_SOURCE=artifact - else - TEST_CUDA_MAJORS=$(jq -c '.jobs.test_cuda_majors' <<< "$WORKPLAN") - PATHFINDER_SOURCE=$(jq -r '.sources.pathfinder' <<< "$WORKPLAN") - fi - - # Apply matrix filter; reject custom DRIVER + FLAVOR=wsl (the - # in-container driver swap doesn't work under WSL); add a - # RUNNER_DRIVER field that maps any custom version back to - # 'latest' (the install script swaps the driver itself, so we - # need to land on the runner that ships with the most recent - # pre-installed driver); wrap in include structure. - MATRIX=$(echo "$TEST_MATRIX" | jq -c \ - --argjson test_cuda_majors "$TEST_CUDA_MAJORS" \ - --argjson bindings_packages "$BINDINGS_PACKAGES" \ - --arg default_bindings_source_dir "$CURRENT_BINDINGS_SOURCE_DIR" \ - --arg pathfinder_source "$PATHFINDER_SOURCE" \ - --argjson workplan "${WORKPLAN:-null}" \ - --arg test_mode "$TEST_MODE" \ - '${{ inputs.matrix_filter }} - | map( - . as $row - | ("cu" + ($row.CUDA_VER | split(".")[0])) as $cuda_variant - | ($bindings_packages | map(select(.toolkit_version == $row.CUDA_VER)) | first) as $bindings_package - | $row + { - CUDA_VARIANT: $cuda_variant, - BINDINGS_SOURCE: (if $bindings_package == null then "floor" else "local" end), - BINDINGS_SOURCE_DIR: ($bindings_package.package_root // ""), - DEFAULT_BINDINGS_SOURCE_DIR: $default_bindings_source_dir, - PATHFINDER_SOURCE: $pathfinder_source - } - ) - | map(select($test_cuda_majors[.CUDA_VARIANT] == true)) - | map(. as $row | . + { - SUITES: (if $test_mode != "standard" then $test_mode else - [if $workplan == null or $workplan.modules.pathfinder.needs_test then "pathfinder" else empty end, - if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.bindings.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "bindings" + ($row.CUDA_VER | split(".")[0]) else empty end, - if $workplan == null or $workplan.modules.core.cuda_majors[$row.CUDA_VARIANT].needs_test then "core" + ($row.CUDA_VER | split(".")[0]) else empty end, - if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "meta" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) - }) - | map(select(.SUITES != "")) - | if any(.[]; .DRIVER != "latest" and .DRIVER != "earliest" and .FLAVOR == "wsl") then "Error: custom DRIVER is not supported with FLAVOR=wsl\n" | halt_error(1) else . end - | map(. + {RUNNER_DRIVER: (if .DRIVER == "latest" or .DRIVER == "earliest" then .DRIVER else "latest" end)}) - | if (. | length) > 0 then {include: .} else "Error: Empty matrix after CUDA-major workplan filtering\n" | halt_error(1) end') - - # Compatibility nightly modes intentionally use published floor bindings. - # Standard PR/release runs must retain each selected local bindings line. - if [[ "$TEST_MODE" == "standard" && "$BUILD_TYPE" == "pull-request" ]]; then - jq -en --argjson packages "$BINDINGS_PACKAGES" \ - --argjson enabled "$TEST_CUDA_MAJORS" --argjson matrix "$MATRIX" \ - --argjson workplan "${WORKPLAN:-null}" ' - [$packages[] | . as $package - | select($enabled[.cuda_variant] == true) - | select($workplan == null or - $workplan.modules.bindings.package_roots[.package_root].needs_test or - $workplan.modules.python.package_roots[.package_root].needs_test) - | select(all($matrix.include[]; - .BINDINGS_SOURCE != "local" or .BINDINGS_SOURCE_DIR != $package.package_root)) - | .package_root] as $missing - | if $missing | length == 0 then true else - error("filtered test matrix omits required local-wheel coverage: \($missing | join(", "))") end - ' > /dev/null - fi + # Keep the caller's free-form jq filter; shared Python code handles + # source selection, test suites, runner routing, and coverage checks. + MATRIX=$(jq -c '${{ inputs.matrix_filter }}' <<< "$TEST_MATRIX" \ + | python3 -m ci.tools.select_test_matrix --platform linux) { echo '### Selected wheel test coverage' diff --git a/.github/workflows/test-wheel-windows.yml b/.github/workflows/test-wheel-windows.yml index e20688d4174..7fcc160e96e 100644 --- a/.github/workflows/test-wheel-windows.yml +++ b/.github/workflows/test-wheel-windows.yml @@ -88,75 +88,10 @@ jobs: # Read base matrix from YAML file for the specific architecture TEST_MATRIX=$(yq -o json ".windows[\"${MATRIX_TYPE}\"] | map(select(.ARCH == \"${ARCH}\"))" ci/test-matrix.yml) - BINDINGS_PACKAGES=$(jq -c '.package_roots' <<< "$BINDINGS_CONFIG") - CURRENT_BINDINGS_SOURCE_DIR=$(jq -r ' - .[] | select(.release_status == "current") | .package_root - ' <<< "$BINDINGS_PACKAGES") - - if [[ -z "$WORKPLAN" ]]; then - TEST_CUDA_MAJORS=$(jq -c ' - [.[].cuda_variant] | map({key: ., value: true}) | from_entries - ' <<< "$BINDINGS_PACKAGES") - PATHFINDER_SOURCE=artifact - else - TEST_CUDA_MAJORS=$(jq -c '.jobs.test_cuda_majors' <<< "$WORKPLAN") - PATHFINDER_SOURCE=$(jq -r '.sources.pathfinder' <<< "$WORKPLAN") - fi - - # Apply matrix filter; add a RUNNER_DRIVER field that maps any - # custom DRIVER version back to 'latest' (install_gpu_driver.ps1 - # swaps the driver itself, so the runner must be the one that - # ships the most recent pre-installed driver); wrap in include. - MATRIX=$(echo "$TEST_MATRIX" | jq -c \ - --argjson test_cuda_majors "$TEST_CUDA_MAJORS" \ - --argjson bindings_packages "$BINDINGS_PACKAGES" \ - --arg default_bindings_source_dir "$CURRENT_BINDINGS_SOURCE_DIR" \ - --arg pathfinder_source "$PATHFINDER_SOURCE" \ - --argjson workplan "${WORKPLAN:-null}" \ - --arg test_mode "$TEST_MODE" \ - '${{ inputs.matrix_filter }} - | map( - . as $row - | ("cu" + ($row.CUDA_VER | split(".")[0])) as $cuda_variant - | ($bindings_packages | map(select(.toolkit_version == $row.CUDA_VER)) | first) as $bindings_package - | $row + { - CUDA_VARIANT: $cuda_variant, - BINDINGS_SOURCE: (if $bindings_package == null then "floor" else "local" end), - BINDINGS_SOURCE_DIR: ($bindings_package.package_root // ""), - DEFAULT_BINDINGS_SOURCE_DIR: $default_bindings_source_dir, - PATHFINDER_SOURCE: $pathfinder_source - } - ) - | map(select($test_cuda_majors[.CUDA_VARIANT] == true)) - | map(. as $row | . + { - SUITES: (if $test_mode != "standard" then $test_mode else - [if $workplan == null or $workplan.modules.pathfinder.needs_test then "pathfinder" else empty end, - if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.bindings.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "bindings" + ($row.CUDA_VER | split(".")[0]) else empty end, - if $workplan == null or $workplan.modules.core.cuda_majors[$row.CUDA_VARIANT].needs_test then "core" + ($row.CUDA_VER | split(".")[0]) else empty end, - if $row.BINDINGS_SOURCE == "local" and ($workplan == null or $workplan.modules.python.package_roots[$row.BINDINGS_SOURCE_DIR].needs_test) then "meta" + ($row.CUDA_VER | split(".")[0]) else empty end] | join("+") end) - }) - | map(select(.SUITES != "")) - | map(. + {RUNNER_DRIVER: (if .DRIVER == "latest" or .DRIVER == "earliest" then .DRIVER else "latest" end)}) - | if (. | length) > 0 then {include: .} else "Error: Empty matrix after CUDA-major workplan filtering\n" | halt_error(1) end') - - # Compatibility nightly modes intentionally use published floor bindings. - # Standard PR/release runs must retain each selected local bindings line. - if [[ "$TEST_MODE" == "standard" && "$BUILD_TYPE" == "pull-request" ]]; then - jq -en --argjson packages "$BINDINGS_PACKAGES" \ - --argjson enabled "$TEST_CUDA_MAJORS" --argjson matrix "$MATRIX" \ - --argjson workplan "${WORKPLAN:-null}" ' - [$packages[] | . as $package - | select($enabled[.cuda_variant] == true) - | select($workplan == null or - $workplan.modules.bindings.package_roots[.package_root].needs_test or - $workplan.modules.python.package_roots[.package_root].needs_test) - | select(all($matrix.include[]; - .BINDINGS_SOURCE != "local" or .BINDINGS_SOURCE_DIR != $package.package_root)) - | .package_root] as $missing - | if $missing | length == 0 then true else - error("filtered test matrix omits required local-wheel coverage: \($missing | join(", "))") end - ' > /dev/null - fi + # Keep the caller's free-form jq filter; shared Python code handles + # source selection, test suites, runner routing, and coverage checks. + MATRIX=$(jq -c '${{ inputs.matrix_filter }}' <<< "$TEST_MATRIX" \ + | python3 -m ci.tools.select_test_matrix --platform windows) { echo '### Selected wheel test coverage' diff --git a/ci/tools/select_test_matrix.py b/ci/tools/select_test_matrix.py new file mode 100644 index 00000000000..e9cf82d243c --- /dev/null +++ b/ci/tools/select_test_matrix.py @@ -0,0 +1,113 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Select wheel-test rows and their local or published bindings sources.""" + +from __future__ import annotations + +import argparse +import json +import os +import sys +from typing import Any + + +def select_test_matrix( + rows: list[dict[str, Any]], + packages: list[dict[str, Any]], + *, + workplan: dict[str, Any] | None = None, + build_type: str = "pull-request", + test_mode: str = "standard", + platform: str = "linux", +) -> dict[str, list[dict[str, Any]]]: + """Apply the workplan after the caller's optional jq matrix filter.""" + current_root = next(package["package_root"] for package in packages if package["release_status"] == "current") + enabled = ( + {package["cuda_variant"]: True for package in packages} + if workplan is None + else workplan["jobs"]["test_cuda_majors"] + ) + modules = None if workplan is None else workplan["modules"] + selected = [] + for source_row in rows: + major = source_row["CUDA_VER"].split(".")[0] + variant = f"cu{major}" + if not enabled.get(variant, False): + continue + package = next((package for package in packages if package["toolkit_version"] == source_row["CUDA_VER"]), None) + root = "" if package is None else package["package_root"] + suites = [] + if test_mode != "standard": + suites.append(test_mode) + else: + if modules is None or modules["pathfinder"]["needs_test"]: + suites.append("pathfinder") + if package is not None and (modules is None or modules["bindings"]["package_roots"][root]["needs_test"]): + suites.append(f"bindings{major}") + if modules is None or modules["core"]["cuda_majors"][variant]["needs_test"]: + suites.append(f"core{major}") + if package is not None and (modules is None or modules["python"]["package_roots"][root]["needs_test"]): + suites.append(f"meta{major}") + if not suites: + continue + driver = source_row["DRIVER"] + # Custom versions are installed after scheduling on a latest-driver + # runner. WSL cannot perform that driver swap. + runner_driver = driver if driver in ("latest", "earliest") else "latest" + if platform == "linux" and runner_driver != driver and source_row.get("FLAVOR") == "wsl": + raise ValueError("custom DRIVER is not supported with FLAVOR=wsl") + selected.append( + { + **source_row, + "CUDA_VARIANT": variant, + "BINDINGS_SOURCE": "floor" if package is None else "local", + "BINDINGS_SOURCE_DIR": root, + "DEFAULT_BINDINGS_SOURCE_DIR": current_root, + "PATHFINDER_SOURCE": "artifact" if workplan is None else workplan["sources"]["pathfinder"], + "SUITES": "+".join(suites), + "RUNNER_DRIVER": runner_driver, + } + ) + if not selected: + raise ValueError("Empty matrix after CUDA-major workplan filtering") + # Nightly integrations may deliberately use published bindings with older + # toolkits. Ordinary PRs must not silently lose a required local-wheel row. + if test_mode == "standard" and build_type == "pull-request": + covered = {row["BINDINGS_SOURCE_DIR"] for row in selected if row["BINDINGS_SOURCE"] == "local"} + missing = [ + package["package_root"] + for package in packages + if enabled.get(package["cuda_variant"], False) + and ( + modules is None + or modules["bindings"]["package_roots"][package["package_root"]]["needs_test"] + or modules["python"]["package_roots"][package["package_root"]]["needs_test"] + ) + and package["package_root"] not in covered + ] + if missing: + raise ValueError(f"filtered test matrix omits required local-wheel coverage: {', '.join(missing)}") + return {"include": selected} + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--platform", choices=("linux", "windows"), required=True) + args = parser.parse_args() + try: + result = select_test_matrix( + json.load(sys.stdin), + json.loads(os.environ["BINDINGS_CONFIG"])["package_roots"], + workplan=json.loads(os.environ.get("WORKPLAN") or "null"), + build_type=os.environ["BUILD_TYPE"], + test_mode=os.environ["TEST_MODE"], + platform=args.platform, + ) + except ValueError as error: + parser.error(str(error)) + print(json.dumps(result, separators=(",", ":"))) + + +if __name__ == "__main__": + main() diff --git a/ci/tools/tests/test_select_test_matrix.py b/ci/tools/tests/test_select_test_matrix.py new file mode 100644 index 00000000000..7e913fa8a0d --- /dev/null +++ b/ci/tools/tests/test_select_test_matrix.py @@ -0,0 +1,71 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import pytest + +from ci.tools.select_test_matrix import select_test_matrix + +PACKAGES = [ + { + "package_root": "bindings12", + "toolkit_version": "12.9.1", + "cuda_variant": "cu12", + "release_status": "maintenance", + }, + {"package_root": "bindings13", "toolkit_version": "13.4.2", "cuda_variant": "cu13", "release_status": "current"}, +] + + +def rows(*toolkits): + return [{"CUDA_VER": toolkit, "DRIVER": "latest"} for toolkit in toolkits] + + +def plan(*, bindings=False, core=True, meta=False): + return { + "jobs": {"test_cuda_majors": {"cu12": True, "cu13": False}}, + "sources": {"pathfinder": "artifact"}, + "modules": { + "pathfinder": {"needs_test": False}, + "bindings": {"package_roots": {package["package_root"]: {"needs_test": bindings} for package in PACKAGES}}, + "core": {"cuda_majors": {"cu12": {"needs_test": core}, "cu13": {"needs_test": core}}}, + "python": {"package_roots": {package["package_root"]: {"needs_test": meta} for package in PACKAGES}}, + }, + } + + +@pytest.mark.agent_authored(model="gpt-6.1-sol") +def test_exact_toolkit_rows_use_local_bindings_and_older_toolkits_use_published_floors(): + matrix = select_test_matrix(rows("12.9.1", "12.6.3", "13.4.2", "13.0.2"), PACKAGES) + + assert [(row["CUDA_VARIANT"], row["BINDINGS_SOURCE"], row["BINDINGS_SOURCE_DIR"]) for row in matrix["include"]] == [ + ("cu12", "local", "bindings12"), + ("cu12", "floor", ""), + ("cu13", "local", "bindings13"), + ("cu13", "floor", ""), + ] + + +@pytest.mark.agent_authored(model="gpt-6.1-sol") +def test_workplan_retains_only_the_required_cuda_major_and_suites(): + matrix = select_test_matrix( + rows("12.9.1", "12.6.3", "13.4.2"), PACKAGES, workplan=plan(bindings=True, core=False, meta=True) + ) + + # Without Core or Pathfinder tests the older-toolkit row has no applicable + # suites. The required maintenance bindings/metapackage row must remain. + assert [(row["CUDA_VER"], row["BINDINGS_SOURCE_DIR"]) for row in matrix["include"]] == [("12.9.1", "bindings12")] + + +@pytest.mark.parametrize("component", ("bindings", "meta")) +@pytest.mark.agent_authored(model="gpt-6.1-sol") +def test_filter_cannot_silently_drop_required_local_wheel_coverage(component): + with pytest.raises(ValueError, match="omits required local-wheel coverage: bindings12"): + select_test_matrix(rows("12.6.3", "13.4.2"), PACKAGES, workplan=plan(**{component: True})) + + +@pytest.mark.parametrize("test_mode", ("nightly-pytorch", "standard")) +@pytest.mark.agent_authored(model="gpt-6.1-sol") +def test_nightly_subsets_may_use_published_floor_bindings(test_mode): + matrix = select_test_matrix(rows("12.6.3"), PACKAGES, build_type="nightly", test_mode=test_mode) + + assert [row["BINDINGS_SOURCE"] for row in matrix["include"]] == ["floor"] From 94af7a2291985788384fc3b3e0f264435646aac2 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 14:12:25 -0700 Subject: [PATCH 09/19] Remove obsolete artifact filters from CI run lookup Signed-off-by: Ralf W. Grosse-Kunstleve --- ci/tools/lookup-run-id | 57 +++--------------------------------------- 1 file changed, 4 insertions(+), 53 deletions(-) diff --git a/ci/tools/lookup-run-id b/ci/tools/lookup-run-id index 89833cfe1bd..b3b07471a30 100755 --- a/ci/tools/lookup-run-id +++ b/ci/tools/lookup-run-id @@ -24,14 +24,11 @@ Usage: Options: --tag Find run by git tag (requires local git repo with the tag) --branch Find latest successful run on the given branch - --artifact Require an unexpired artifact matching this shell glob - (repeatable; branch mode only) --head-sha Also print the run's head commit SHA (second line) Examples: $0 --tag v13.0.1 NVIDIA/cuda-python $0 --branch main NVIDIA/cuda-python - $0 --branch 12.9.x --artifact 'cuda-bindings-python313-*' NVIDIA/cuda-python $0 --branch main --head-sha NVIDIA/cuda-python "CI" EOF exit 1 @@ -41,7 +38,6 @@ EOF MODE="" REF="" HEAD_SHA_FLAG=0 -ARTIFACT_PATTERNS=() while [[ $# -gt 0 ]]; do case "${1}" in @@ -53,9 +49,6 @@ while [[ $# -gt 0 ]]; do [[ $# -ge 2 ]] || usage [[ -n "${MODE}" && "${MODE}" != "branch" ]] && { echo "Error: --tag and --branch are mutually exclusive" >&2; exit 1; } MODE="branch"; REF="${2}"; shift 2 ;; - --artifact) - [[ $# -ge 2 ]] || usage - ARTIFACT_PATTERNS+=("${2}"); shift 2 ;; --head-sha) HEAD_SHA_FLAG=1; shift ;; -h|--help) @@ -78,11 +71,6 @@ WORKFLOW_NAME="${1:-CI}" if [[ -z "${REPOSITORY}" ]]; then usage; fi -if [[ "${MODE}" != "branch" && ${#ARTIFACT_PATTERNS[@]} -gt 0 ]]; then - echo "Error: --artifact is only supported with --branch" >&2 - exit 1 -fi - # ── Prerequisite checks ── if [[ -z "${GH_TOKEN:-}" ]]; then echo "Error: GH_TOKEN environment variable is required" >&2 @@ -99,8 +87,8 @@ done # ── Mode: branch ── # # Walk the branch's commit history from HEAD and return the first commit -# whose workflow has a successful run matching any required artifact -# patterns. The one Actions-API filter used is ?head_sha=, which is +# whose workflow has a successful run. The one Actions-API filter used is +# ?head_sha=, which is # not on the list of filters flagged as returning stale/cached slices in # https://github.com/orgs/community/discussions/24626. if [[ "${MODE}" == "branch" ]]; then @@ -142,13 +130,7 @@ if [[ "${MODE}" == "branch" ]]; then exit 1 fi - if [[ ${#ARTIFACT_PATTERNS[@]} -gt 0 ]]; then - echo "Requiring unexpired artifacts matching:" >&2 - printf ' - %s\n' "${ARTIFACT_PATTERNS[@]}" >&2 - fi - - # Walk branch commits newest-first; accept the first commit with a - # successful run that passes the artifact check. + # Walk branch commits newest-first; accept the first successful run. COMMIT_SCAN_LIMIT="${LOOKUP_RUN_ID_COMMIT_SCAN_LIMIT:-200}" RUN_ID="" HEAD_SHA="" @@ -186,37 +168,6 @@ if [[ "${MODE}" == "branch" ]]; then for ((i=0; i&2 - exit 1 - fi - - for pattern in "${ARTIFACT_PATTERNS[@]}"; do - pattern_matched=0 - while IFS= read -r artifact_name; do - # The caller supplies a shell glob; RHS must stay unquoted. - # shellcheck disable=SC2053 - if [[ -n "${artifact_name}" && "${artifact_name}" == ${pattern} ]]; then - pattern_matched=1 - break - fi - done <<< "${ARTIFACT_NAMES}" - if [[ ${pattern_matched} == 0 ]]; then - missing_patterns+=("${pattern}") - fi - done - fi - - if [[ ${#missing_patterns[@]} -gt 0 ]]; then - echo "Skipping run ${candidate_id} (sha ${candidate_sha:0:12}, ${candidate_created_at}); missing unexpired artifact(s): ${missing_patterns[*]}" >&2 - continue - fi RUN_ID="${candidate_id}" HEAD_SHA="${candidate_sha}" @@ -228,7 +179,7 @@ if [[ "${MODE}" == "branch" ]]; then done if [[ -z "${RUN_ID}" ]]; then - echo "Error: No successful '${WORKFLOW_NAME}' run with required artifacts found in the ${commits_scanned} most-recent commits of branch '${REF}'" >&2 + echo "Error: No successful '${WORKFLOW_NAME}' run found in the ${commits_scanned} most-recent commits of branch '${REF}'" >&2 echo "Branch HEAD: ${BRANCH_HEAD_SHA}" >&2 exit 1 fi From a916cce7045b62c9ef0c1e1950254e3374ea658a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 14:12:37 -0700 Subject: [PATCH 10/19] Keep CI source and wheel tests focused on silent failures Signed-off-by: Ralf W. Grosse-Kunstleve --- ci/tools/tests/test_merge_cuda_core_wheels.py | 21 +- ci/tools/tests/test_test_sources.py | 242 ------------------ 2 files changed, 1 insertion(+), 262 deletions(-) diff --git a/ci/tools/tests/test_merge_cuda_core_wheels.py b/ci/tools/tests/test_merge_cuda_core_wheels.py index bdabb168819..b1eab55e291 100644 --- a/ci/tools/tests/test_merge_cuda_core_wheels.py +++ b/ci/tools/tests/test_merge_cuda_core_wheels.py @@ -1,31 +1,12 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -from pathlib import Path from zipfile import ZipFile import pytest from wheel.wheelfile import WheelFile -from ci.tools.merge_cuda_core_wheels import cuda_variant_from_wheel, merge_wheels - - -@pytest.mark.agent_authored(model="gpt-5.6-sol") -@pytest.mark.parametrize( - ("name", "expected"), - [ - ("cuda_core-1.2.3-cp312-cp312-manylinux_x86_64.cu12.whl", "cu12"), - ("cuda_core-2.0.0-cp315-cp315-win_amd64.cu14.whl", "cu14"), - ], -) -def test_cuda_variant_from_wheel(name, expected): - assert cuda_variant_from_wheel(Path(name)) == expected - - -@pytest.mark.agent_authored(model="gpt-5.6-sol") -def test_cuda_variant_from_wheel_rejects_missing_suffix(): - with pytest.raises(ValueError, match=r"does not contain a \.cuN suffix"): - cuda_variant_from_wheel(Path("cuda_core-1.2.3-py3-none-any.whl")) +from ci.tools.merge_cuda_core_wheels import merge_wheels @pytest.mark.agent_authored(model="gpt-6-astra") diff --git a/ci/tools/tests/test_test_sources.py b/ci/tools/tests/test_test_sources.py index e99c0ad4c16..c7d4add8a90 100644 --- a/ci/tools/tests/test_test_sources.py +++ b/ci/tools/tests/test_test_sources.py @@ -12,11 +12,8 @@ import pytest -from ci.tools.bindings_config import load_config - REPO_ROOT = Path(__file__).resolve().parents[3] RUN_TESTS = REPO_ROOT / "ci" / "tools" / "run-tests" -ENV_VARS = REPO_ROOT / "ci" / "tools" / "env-vars" def _write_command(directory: Path, name: str, body: str) -> None: @@ -57,245 +54,6 @@ def _run_tests_env(tmp_path: Path) -> tuple[dict[str, str], Path]: return env, command_log -def _run_env_vars( - tmp_path: Path, - *, - bindings_source: str, - pathfinder_source: str, - cuda_version: str = "13.3.0", - bindings_root: str = "cuda_bindings", -) -> subprocess.CompletedProcess[str]: - for relative in ( - f"{bindings_root}/dist", - f"{bindings_root}/tests/cython", - "cuda_core/dist", - "cuda_core/tests/cython", - "cuda_core/tests/test_binaries", - ): - (tmp_path / relative).mkdir(parents=True, exist_ok=True) - github_env = tmp_path / "github-env" - github_path = tmp_path / "github-path" - env = { - **os.environ, - "BINDINGS_SOURCE": bindings_source, - "CUDA_VER": cuda_version, - "GITHUB_ENV": str(github_env), - "GITHUB_PATH": str(github_path), - "HOST_PLATFORM": "linux-64", - "LOCAL_CTK": "0", - "PATHFINDER_SOURCE": pathfinder_source, - "PY_VER": "3.13", - "SHA": "abcdef", - "SKIP_BINDINGS_TEST_OVERRIDE": "0", - } - if bindings_source == "local": - env["BINDINGS_SOURCE_DIR"] = bindings_root - else: - env["DEFAULT_BINDINGS_SOURCE_DIR"] = bindings_root - return subprocess.run( # noqa: S603 - invokes the repository script under test - [str(ENV_VARS), "test"], - cwd=tmp_path, - env=env, - check=False, - capture_output=True, - text=True, - ) - - -def _read_github_env(path: Path) -> dict[str, str]: - return dict(line.split("=", 1) for line in path.read_text(encoding="utf-8").splitlines()) - - -@pytest.mark.agent_authored(model="gpt-5.6-sol") -def test_env_vars_rejects_unknown_mode() -> None: - result = subprocess.run( # noqa: S603 - invokes the repository script under test - [str(ENV_VARS), "unknown"], - check=False, - capture_output=True, - text=True, - ) - - assert result.returncode == 1 - assert "build mode must be build or test" in result.stderr - - -@pytest.mark.agent_authored(model="gpt-5.6") -def test_build_env_uses_registry_packages_without_generic_bindings_aliases(tmp_path: Path) -> None: - github_env = tmp_path / "github-env" - env = { - **os.environ, - "GITHUB_ENV": str(github_env), - "GITHUB_PATH": str(tmp_path / "github-path"), - "HOST_PLATFORM": "linux-64", - "PY_VER": "3.13", - "SHA": "abcdef0", - } - - result = subprocess.run( # noqa: S603 - invokes the repository script under test - [str(ENV_VARS), "build"], - cwd=REPO_ROOT, - env=env, - check=False, - capture_output=True, - text=True, - ) - - assert result.returncode == 0, result.stderr - values = _read_github_env(github_env) - config = load_config() - for status in ("current", "maintenance"): - package = config.package_for_release_status(status) - prefix = status.upper() - assert values[f"{prefix}_BINDINGS_ROOT"] == package.package_root - assert values[f"{prefix}_CUDA_VERSION"] == package.toolkit_version - assert values[f"{prefix}_CUDA_MAJOR"] == package.cuda_major - assert values[f"{prefix}_CUDA_VARIANT"] == package.cuda_variant - assert values[f"{prefix}_BINDINGS_ARTIFACT_NAME"].endswith("-abcdef0") - - assert ( - not { - "CUDA_BINDINGS_ARTIFACT_BASENAME", - "CUDA_BINDINGS_ARTIFACT_NAME", - "CUDA_BINDINGS_ARTIFACTS_DIR", - "CUDA_BINDINGS_CYTHON_TESTS_DIR", - } - & values.keys() - ) - - -@pytest.mark.parametrize("wheel_count", [0, 2]) -@pytest.mark.agent_authored(model="gpt-5.6") -def test_artifact_pathfinder_requires_exactly_one_wheel(tmp_path: Path, wheel_count: int) -> None: - env, _ = _run_tests_env(tmp_path) - env["PATHFINDER_SOURCE"] = "artifact" - for index in range(wheel_count): - (tmp_path / "cuda_pathfinder" / f"cuda_pathfinder-{index}.whl").touch() - - result = subprocess.run( # noqa: S603 - invokes the repository script under test - [str(RUN_TESTS), "pathfinder"], - cwd=tmp_path, - env=env, - check=False, - capture_output=True, - text=True, - ) - - assert result.returncode != 0 - assert "Expected exactly one cuda-pathfinder wheel" in result.stderr - - -@pytest.mark.agent_authored(model="gpt-5.6") -def test_artifact_pathfinder_installs_the_only_wheel(tmp_path: Path) -> None: - env, command_log = _run_tests_env(tmp_path) - env["PATHFINDER_SOURCE"] = "artifact" - wheel = tmp_path / "cuda_pathfinder" / "cuda_pathfinder-1.0-py3-none-any.whl" - wheel.touch() - - subprocess.run( # noqa: S603 - invokes the repository script under test - [str(RUN_TESTS), "pathfinder"], - cwd=tmp_path, - env=env, - check=True, - capture_output=True, - text=True, - ) - - assert f"pip install ./{wheel.name} --group test" in command_log.read_text(encoding="utf-8") - - -@pytest.mark.agent_authored(model="gpt-5.6") -def test_published_pathfinder_is_limited_to_bindings_release_tests(tmp_path: Path) -> None: - env, _ = _run_tests_env(tmp_path) - env["PATHFINDER_SOURCE"] = "published" - - result = subprocess.run( # noqa: S603 - invokes the repository script under test - [str(RUN_TESTS), "pathfinder"], - cwd=tmp_path, - env=env, - check=False, - capture_output=True, - text=True, - ) - - assert result.returncode != 0 - assert "published for bindings release tests" in result.stderr - - -@pytest.mark.agent_authored(model="gpt-5.6") -def test_published_pathfinder_supports_bindings_release_tests(tmp_path: Path) -> None: - env, command_log = _run_tests_env(tmp_path) - env.update( - CUDA_BINDINGS_ARTIFACTS_DIR=str(tmp_path / "bindings-artifacts"), - CUDA_BINDINGS_ROOT="cuda_bindings", - LOCAL_CTK="1", - PATHFINDER_SOURCE="published", - SANITIZER_CMD="", - SKIP_CYTHON_TEST="1", - ) - (tmp_path / "cuda_bindings").mkdir() - (tmp_path / "cuda_bindings" / "pyproject.toml").write_text("[dependency-groups]\ntest = []\n", encoding="utf-8") - (tmp_path / "bindings-artifacts").mkdir() - (tmp_path / "bindings-artifacts" / "cuda_bindings-13.3.whl").touch() - - subprocess.run( # noqa: S603 - invokes the repository script under test - [str(RUN_TESTS), "bindings"], - cwd=tmp_path, - env=env, - check=True, - capture_output=True, - text=True, - ) - - calls = command_log.read_text(encoding="utf-8").splitlines() - assert calls[0].startswith("pip install cuda-pathfinder --group test") - assert calls[1].startswith("python -m pip install ") - - -@pytest.mark.parametrize( - ("bindings_source", "cuda_version", "bindings_root", "expected_artifact"), - [ - ("local", "13.4.2", "cuda_bindings", "cuda-python-wheel-cuda13.4.2"), - ("local", "12.9.1", "cuda_bindings_12", "cuda-python-wheel-cuda12.9.1"), - ("floor", "13.0.2", "cuda_bindings", None), - ("floor", "12.6.3", "cuda_bindings", None), - ], -) -@pytest.mark.agent_authored(model="gpt-6-astra") -def test_cuda_python_artifact_name_exists_only_for_local_bindings( - tmp_path: Path, - bindings_source: str, - cuda_version: str, - bindings_root: str, - expected_artifact: str | None, -) -> None: - result = _run_env_vars( - tmp_path, - bindings_source=bindings_source, - pathfinder_source="artifact", - cuda_version=cuda_version, - bindings_root=bindings_root, - ) - - assert result.returncode == 0, result.stderr - github_env = _read_github_env(tmp_path / "github-env") - assert { - "CUDA_BINDINGS_ARTIFACT_BASENAME", - "CUDA_BINDINGS_ARTIFACT_NAME", - "CUDA_BINDINGS_ARTIFACTS_DIR", - "CUDA_BINDINGS_CYTHON_TESTS_DIR", - "CUDA_CORE_CYTHON_TEST_ARTIFACT_NAME", - } <= github_env.keys() - assert github_env["BINDINGS_SOURCE"] == bindings_source - assert github_env["CUDA_BINDINGS_ROOT"] == bindings_root - assert github_env["SKIP_CUDA_BINDINGS_TEST"] == ("1" if bindings_source == "floor" else "0") - assert github_env["SKIP_CYTHON_TEST"] == ("1" if bindings_source == "floor" else "0") - assert github_env["CUDA_CORE_CYTHON_TEST_ARTIFACT_NAME"].endswith(f"-cu{cuda_version.split('.')[0]}-tests") - if expected_artifact is None: - assert "CUDA_PYTHON_ARTIFACT_NAME" not in github_env - else: - assert github_env["CUDA_PYTHON_ARTIFACT_NAME"] == expected_artifact - - @pytest.mark.agent_authored(model="gpt-6-astra") @pytest.mark.parametrize(("cuda_version", "wheel_floor"), [("12.6.3", "12.9.9"), ("13.0.2", "13.4.2")]) def test_core_install_uses_wheel_floor_with_older_toolkit(tmp_path: Path, cuda_version: str, wheel_floor: str) -> None: From ece31e6962a42d68baf1dbcbbcdc41985750a029 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 14:14:59 -0700 Subject: [PATCH 11/19] Keep matrix tooling separate from artifact source checkouts Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/test-wheel-linux.yml | 11 ++++++++++- .github/workflows/test-wheel-windows.yml | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-wheel-linux.yml b/.github/workflows/test-wheel-linux.yml index 1effabdb8a4..2bc30b81d12 100644 --- a/.github/workflows/test-wheel-linux.yml +++ b/.github/workflows/test-wheel-linux.yml @@ -72,6 +72,15 @@ jobs: with: ref: ${{ inputs.sha || github.sha }} + - name: Checkout CI matrix helper + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # Artifact sources can predate this helper; use the workflow's revision. + ref: ${{ github.sha }} + path: .ci-control + sparse-checkout: ci/tools/select_test_matrix.py + sparse-checkout-cone-mode: false + - name: Validate Test Type run: | if [[ "$BUILD_TYPE" != "pull-request" ]] && [[ "$BUILD_TYPE" != "nightly" ]] && [[ "$BUILD_TYPE" != "branch" ]]; then @@ -94,7 +103,7 @@ jobs: # Keep the caller's free-form jq filter; shared Python code handles # source selection, test suites, runner routing, and coverage checks. MATRIX=$(jq -c '${{ inputs.matrix_filter }}' <<< "$TEST_MATRIX" \ - | python3 -m ci.tools.select_test_matrix --platform linux) + | python3 .ci-control/ci/tools/select_test_matrix.py --platform linux) { echo '### Selected wheel test coverage' diff --git a/.github/workflows/test-wheel-windows.yml b/.github/workflows/test-wheel-windows.yml index 7fcc160e96e..45cd4b6e190 100644 --- a/.github/workflows/test-wheel-windows.yml +++ b/.github/workflows/test-wheel-windows.yml @@ -70,6 +70,15 @@ jobs: with: ref: ${{ inputs.sha || github.sha }} + - name: Checkout CI matrix helper + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # Artifact sources can predate this helper; use the workflow's revision. + ref: ${{ github.sha }} + path: .ci-control + sparse-checkout: ci/tools/select_test_matrix.py + sparse-checkout-cone-mode: false + - name: Validate Test Type run: | if [[ "$BUILD_TYPE" != "pull-request" ]] && [[ "$BUILD_TYPE" != "nightly" ]] && [[ "$BUILD_TYPE" != "branch" ]]; then @@ -91,7 +100,7 @@ jobs: # Keep the caller's free-form jq filter; shared Python code handles # source selection, test suites, runner routing, and coverage checks. MATRIX=$(jq -c '${{ inputs.matrix_filter }}' <<< "$TEST_MATRIX" \ - | python3 -m ci.tools.select_test_matrix --platform windows) + | python3 .ci-control/ci/tools/select_test_matrix.py --platform windows) { echo '### Selected wheel test coverage' From b8e4d31cba9f7f8f8752a9ff24cb91e25ae08ce0 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 14:23:23 -0700 Subject: [PATCH 12/19] Align build and test documentation with both bindings roots Signed-off-by: Ralf W. Grosse-Kunstleve --- CONTRIBUTING.md | 28 ++++++------- ci/README.md | 52 +++++++++++++++++++++--- cuda_bindings_12/docs/README.md | 18 ++++++-- cuda_bindings_12/docs/source/install.md | 39 +++++++++++++++--- cuda_bindings_13/docs/README.md | 8 +++- cuda_bindings_13/docs/source/install.rst | 12 ++++-- cuda_bindings_13/docs/source/support.rst | 4 +- cuda_core/docs/source/install.rst | 8 ++-- cuda_python/docs/README.md | 6 ++- 9 files changed, 133 insertions(+), 42 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8773d95210e..192d7d5845d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,9 +28,7 @@ reproducers, documentation improvements, and code changes are welcome. - [CI infrastructure overview](#ci-infrastructure-overview) - [CI Pipeline Flow](#ci-pipeline-flow) - [Pipeline Execution Details](#pipeline-execution-details) - - [Branch-specific Artifact Flow](#branch-specific-artifact-flow) - - [Main Branch](#main-branch) - - [Backport Branches](#backport-branches) + - [Source and Artifact Flow](#source-and-artifact-flow) - [Key Infrastructure Details](#key-infrastructure-details) - [Code coverage](#code-coverage) @@ -445,20 +443,20 @@ The CI pipeline diagram is maintained as Mermaid source in [`ci/ci-pipeline.mmd` - **Build Stage**: Different architectures/operating systems (linux-64, linux-aarch64, win-64) are built in parallel across their respective runners - **Test Stage**: Different architectures/operating systems/CUDA versions are tested in parallel; documentation preview is also built in parallel with testing -### Branch-specific Artifact Flow +### Source and Artifact Flow -#### Main Branch -- **Build** → **Test** → **Documentation** → **Potential Release** -- Artifacts stored as `{component}-python{version}-{platform}-{sha}` -- Full test coverage across all platforms and CUDA versions -- **Artifact flow out**: `cuda-pathfinder` artifacts → backport branches +- Pushes to `main` build and test both registered bindings lines and their + dependent packages from the same source revision. +- Pull requests build affected packages and test their consumers. Unchanged + wheels and test artifacts can reuse a successful exact-baseline CI run; + without a complete usable baseline, CI builds and tests everything. +- Bindings tags select their matching bindings root and metapackage, using + published Pathfinder. They do not require a Core release. +- Other branches retain their own release procedure and compatible tooling. + Main-tree CI no longer fetches CUDA 12 bindings artifacts from `12.9.x`. -#### Backport Branches -- **Build** → **Test** → **Backport PR Creation** -- Artifacts used for validation before creating backport pull requests -- Maintains compatibility with older CUDA versions -- **Artifact flow in**: `cuda-pathfinder` artifacts ← main branch -- **Artifact flow out**: older `cuda-bindings` artifacts → main branch +See [Reading CI Jobs and Summaries](ci/README.md#reading-ci-jobs-and-summaries) +for package/major names, local versus published bindings, and reuse details. ### Key Infrastructure Details diff --git a/ci/README.md b/ci/README.md index 458738ae5b5..4bd4bb12429 100644 --- a/ci/README.md +++ b/ci/README.md @@ -203,12 +203,12 @@ committed lockfiles to address the eMudhra/emSign CA incident; no general lockfile refresh was performed. Re-enable maintenance only after a released Pixi passes both upstream issue -reproducers and repeated byte-stable update/lock/check cycles across all six -workspaces: the repository root, `cuda_pathfinder`, `cuda_bindings_13`, `cuda_core`, -`benchmarks/cuda_bindings`, and `benchmarks/cuda_core`. Verify both `pixi update ---no-install` and `pixi lock`, followed by repeated `pixi lock --check` commands, -converge to unchanged lockfile bytes. Then restore strict freshness checks, -scheduled refreshes, and `PIXI_LOCKED=true` in source-build CI. +reproducers and repeated byte-stable update/lock/check cycles across every +workspace reported by `python ci/tools/list_pixi_workspaces.py`, including both +bindings roots. Verify `pixi update --no-install` and `pixi lock`, followed by +repeated `pixi lock --check` commands, converge to unchanged lockfile bytes. +Then restore strict freshness checks, scheduled refreshes, and `PIXI_LOCKED=true` +in source-build CI. ## Repository Customizations @@ -335,3 +335,43 @@ a plausible but wrong `0.1.dev...` version. The maintenance bootstrap does not automatically establish milestones for the current-major root. Use the same local-preview safeguards while preparing the new source and confirm the resolved version and `git describe` output before retaining its milestone. + +## Reading CI Jobs and Summaries + +A name such as `pathfinder+bindings12+core12+meta12 / py3.11, CTK12.9.1 +(wheels; bindings PR)` identifies the enabled test suites, Python version, +and toolkit. `meta12` means the CUDA 12 `cuda-python` metapackage; `core12` +means Core tested with CUDA 12. The corresponding CUDA 13 suites use `13`. +`pathfinder` is shared across majors. + +The two source descriptions answer different questions: + +- `wheels` or `local CTK` describes how the toolkit libraries are supplied. +- `bindings PR` uses the selected root's artifact from this CI run. Unaffected + packages can reuse exact-baseline wheels, so this label alone does not mean + the bindings were rebuilt for the PR. +- `bindings floor` uses the oldest published bindings supported by the Core + wheel for that CUDA major, as declared in its metadata. These rows test Core + or the selected nightly integration against published bindings, without + running the bindings or metapackage suites. + +Open the change-detection job's **CI workplan** summary and expand its JSON. +The component build/test flags identify selected work; the baseline records +the original run and exact source SHA for reusable artifacts. Reuse requires a +successful push CI run for the exact merge-base commit on the PR's base branch, +with the complete required artifact set. If that baseline is unavailable, CI +builds and tests everything. A bindings-only change reuses the unchanged +merged Core wheel while testing Core against the affected bindings major. + +The platform matrix-setup jobs' **Selected wheel test coverage** summaries +show the final suites, toolkit source, bindings root or published floor, and +GPU. Shared infrastructure changes, regular branch runs, and scheduled CI +cover both majors; a bindings tag deliberately selects one bindings/metapackage +line and published Pathfinder. Windows ARM64 omits CUDA 12 because that toolkit +has no Windows ARM64 build. + +`ci/tools/select_test_matrix.py` applies the shared selection and local-wheel +coverage rules after each platform reads its source matrix and applies an +optional jq filter. Matrix data comes from the artifact source revision; the +helper comes from the workflow control revision so older artifact sources do +not need to contain newly introduced CI tooling. diff --git a/cuda_bindings_12/docs/README.md b/cuda_bindings_12/docs/README.md index 8b445f41e65..9465dcedf39 100644 --- a/cuda_bindings_12/docs/README.md +++ b/cuda_bindings_12/docs/README.md @@ -1,10 +1,22 @@ # Build the documentation -1. Install the `cuda-bindings` package of the version that we need to document. +Use a separate environment from CUDA 13 documentation builds: both roots +install the same `cuda-bindings` distribution and `cuda.bindings` namespace. +The aggregate `cuda_python/docs/build_all_docs.sh` script builds the current +CUDA 13 line, so build this maintenance documentation separately. + +1. Install the CUDA 12 `cuda-bindings` build that you need to document. 2. Ensure the version is included in the canonical [`nv-versions.json`](../../cuda_bindings_13/docs/nv-versions.json). 3. Build the docs with `./build_docs.sh`. 4. The html artifacts should be available under both `./build/html/latest` and `./build/html/`. -To publish the docs with the built version, it is important to note that the html files of older versions -should be kept intact, in order for the version selection (through `nv-versions.json`) to work. +The Pixi `docs` environment currently installs a published `12.9.*` package. +To document APIs changed in the checkout, install the matching source build +in your documentation environment before running `./build_docs.sh`. + +`build/html/latest` is for local preview only. Follow the selected branch's +release procedure for publication. Maintenance publication must exclude `latest` +and the shared version-selector files so it cannot overwrite the current-major +site. Keep older versioned pages intact; do not publish the entire local build +directory over the shared site. diff --git a/cuda_bindings_12/docs/source/install.md b/cuda_bindings_12/docs/source/install.md index 728c06729a4..cb80bd52720 100644 --- a/cuda_bindings_12/docs/source/install.md +++ b/cuda_bindings_12/docs/source/install.md @@ -6,14 +6,24 @@ * Linux (x86-64, arm64) and Windows (x86-64) * Python 3.11 - 3.15 -* Driver: Linux (450.80.02 or later) Windows (456.38 or later) -* Optionally, NVRTC, nvJitLink, and NVVM from CUDA Toolkit 12.x +* Driver: Linux (525.60.13 or later), Windows (528.33 or later) +* Optionally, NVRTC, nvJitLink, NVVM, nvFatbin, and cuFile (Linux only) from CUDA Toolkit 12.x + +These driver versions are the CUDA 12 minor-version compatibility baseline in the +[CUDA 12.9 release notes](https://docs.nvidia.com/cuda/archive/12.9.1/cuda-toolkit-release-notes/index.html#cuda-driver). +Features introduced with newer drivers and PTX compilation can require a newer +driver; see the +[minor-version compatibility limitations](https://docs.nvidia.com/deploy/cuda-compatibility/minor-version-compatibility.html#application-considerations-for-minor-version-compatibility). ```{note} The optional CUDA Toolkit components can be installed via PyPI, Conda, OS-specific package managers, or local installers (as described in the CUDA Toolkit [Windows](https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html) and [Linux](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html) Installation Guides). ``` -Starting from v12.8.0, `cuda-python` becomes a meta package which currently depends only on `cuda-bindings`; in the future more sub-packages will be added to `cuda-python`. In the instructions below, we still use `cuda-python` as example to serve existing users, but everything is applicable to `cuda-bindings` as well. +The CUDA 12 releases of `cuda-python` are a metapackage that depends directly +on `cuda-bindings`. The examples below use `cuda-python` for existing users; +install `cuda-bindings` directly if you only need the low-level interfaces. + +Both main-tree CUDA 12 packages require Python 3.11 or newer. ## Installing from PyPI @@ -32,6 +42,8 @@ Where the optional dependencies are: * nvidia-cuda-nvrtc-cu12 (Provides NVRTC shared library) * nvidia-nvjitlink-cu12>=12.3 (Provides nvJitLink shared library) * nvidia-cuda-nvcc-cu12 (Provides NVVM shared library) +* nvidia-nvfatbin-cu12 (Provides nvFatbin shared library) +* nvidia-cufile-cu12 (Provides cuFile shared library, Linux only) ## Installing from Conda @@ -43,6 +55,19 @@ $ conda install -c conda-forge cuda-python=12.9 ## Installing from Source +Start with the repository +[recommended clone](https://github.com/NVIDIA/cuda-python/blob/main/CONTRIBUTING.md#recommended-clone). +On native Windows outside WSL, complete its symlink setup before cloning. +CUDA 12 sources live in `cuda_bindings_12/`; CUDA 13 sources have a separate root. +Both build the same `cuda-bindings` distribution, so use a separate Python +environment for each major. + +Versions are derived from reachable `v12.9.*` tags using `setuptools-scm`. +Historical tags from the old maintenance branch may not be ancestors of `main`. +Before a suitable tag is reachable, follow the +[maintenance preview-build guidance](https://github.com/NVIDIA/cuda-python/blob/main/ci/README.md#cuda-bindings-package-root-registry) +in an independent clone; worktrees share tags with the rest of their repository. + ### Requirements * CUDA Toolkit headers[^1] @@ -67,10 +92,12 @@ Only `cydriver`, `cyruntime` and `cynvrtc` are impacted by the header requiremen ### Editable Install -You can use +From the repository root, run: ```console -$ pip install -v -e . +$ cd cuda_bindings_12 +$ python -m pip install -v -e . ``` -to install the module as editable in your current Python environment (e.g. for testing of porting other libraries to use the binding). +This installs the CUDA 12 bindings as editable in your current Python environment +for development and testing. diff --git a/cuda_bindings_13/docs/README.md b/cuda_bindings_13/docs/README.md index 54d670d0917..c0311407c28 100644 --- a/cuda_bindings_13/docs/README.md +++ b/cuda_bindings_13/docs/README.md @@ -1,11 +1,15 @@ # Build the documentation -1. Install the `cuda-bindings` package of the version that we need to document. +1. Install the CUDA 13 `cuda-bindings` build that you need to document. 2. Ensure the version is included in the [`nv-versions.json`](./nv-versions.json). 3. Build the docs with `./build_docs.sh`. 4. The html artifacts should be available under both `./build/html/latest` and `./build/html/`. -Alternatively, we can build all the docs at once by running [`cuda_python/docs/build_all_docs.sh`](../../cuda_python/docs/build_all_docs.sh). +[`cuda_python/docs/build_all_docs.sh`](../../cuda_python/docs/build_all_docs.sh) +builds this current bindings line together with the metapackage, Core, and +Pathfinder documentation. Build [CUDA 12 maintenance documentation](../../cuda_bindings_12/docs/README.md) +separately in its own environment; both roots install the same `cuda-bindings` +distribution and `cuda.bindings` namespace. To publish the docs with the built version, it is important to note that the html files of older versions should be kept intact, in order for the version selection (through `nv-versions.json`) to work. diff --git a/cuda_bindings_13/docs/source/install.rst b/cuda_bindings_13/docs/source/install.rst index 54adde64bb1..39d03c583de 100644 --- a/cuda_bindings_13/docs/source/install.rst +++ b/cuda_bindings_13/docs/source/install.rst @@ -18,7 +18,11 @@ Runtime Requirements The optional CUDA Toolkit components are now installed via the ``cuda-toolkit`` metapackage from PyPI for improved dependency resolution. Components can also be installed via Conda, OS-specific package managers, or local installers (as described in the CUDA Toolkit `Windows `_ and `Linux `_ Installation Guides). -Starting from v12.8.0, ``cuda-python`` becomes a meta package which currently depends only on ``cuda-bindings``; in the future more sub-packages will be added to ``cuda-python``. In the instructions below, we still use ``cuda-python`` as example to serve existing users, but everything is applicable to ``cuda-bindings`` as well. +The CUDA 13 releases of ``cuda-python`` are a metapackage that installs +``cuda-bindings``, ``cuda-core``, and ``cuda-pathfinder``. The examples below use +``cuda-python`` for existing users; install ``cuda-bindings`` directly if you +only need the low-level interfaces. Its ``all`` extra installs the optional +Toolkit components listed below. Free-threading Build Support @@ -133,8 +137,10 @@ Requirements [^2]: The CUDA Runtime static library (``libcudart_static.a`` on Linux, ``cudart_static.lib`` on Windows) is part of the CUDA Toolkit. If using conda packages, it is contained in the ``cuda-cudart-static`` package. [^3]: The version is derived from git tags via ``setuptools-scm``, so the clone -must include tags reaching back to at least the latest ``v*`` tag. Do not use -``--depth`` or ``--no-tags``: a clone without reachable tags can build with a +must include a reachable tag matching the release line configured in this +package's ``pyproject.toml`` (currently ``v13.4.*``). A tag from the other CUDA +major does not determine this package's version. Do not use ``--depth`` or +``--no-tags``: a clone without matching reachable tags can build with a bogus version such as ``0.1.dev1+g0d22cb444``. See `Cloning the repository `_ for details. diff --git a/cuda_bindings_13/docs/source/support.rst b/cuda_bindings_13/docs/source/support.rst index 665c29c029f..b9617826d5c 100644 --- a/cuda_bindings_13/docs/source/support.rst +++ b/cuda_bindings_13/docs/source/support.rst @@ -12,8 +12,8 @@ The ``cuda.bindings`` module has the following support policy: third number in the version string), however, is reserved to reflect Python-only changes and is out of sync with the Toolkit patch version. 2. The module is actively maintained to support the latest CUDA major version and its prior major - version. For example, as of writing the bindings for CUDA 12 & 13 are maintained. Any fix in the - latest bindings would be backported to the prior major version. + version. Both active source trees live on the main branch so applicable fixes can update the + CUDA 12 and CUDA 13 packages in one change. 3. The module supports `CUDA minor version compatibility`_, meaning that ``cuda.bindings`` 12.x supports any Toolkit 12.y. (Whether or not a binding API would actually correctly function depends on the underlying driver and the Toolkit versions, as described in the compatibility diff --git a/cuda_core/docs/source/install.rst b/cuda_core/docs/source/install.rst index 0b4374392b9..c1fcf936e33 100644 --- a/cuda_core/docs/source/install.rst +++ b/cuda_core/docs/source/install.rst @@ -101,10 +101,10 @@ obtain the most recent build, use the following commands: $ # Install the downloaded wheel: $ pip install cuda-core-python312-linux-64-*/cuda_core*.whl[cu13] -Replace ``python312`` with your Python version (e.g. ``python310``, ``python311``, -``python313``, ``python314``, ``python314t``). For aarch64, replace ``linux-64`` -with ``linux-aarch64``; for Windows, use ``win-64``. Replace ``cu13`` with -``cu12`` for CUDA 12.x environments. +Replace ``python312`` with your Python version (e.g. ``python311``, +``python313``, ``python314``, ``python314t``, ``python315``, ``python315t``). +For aarch64, replace ``linux-64`` with ``linux-aarch64``; for Windows, use +``win-64``. Replace ``cu13`` with ``cu12`` for CUDA 12.x environments. .. _cuda-core-source-install: diff --git a/cuda_python/docs/README.md b/cuda_python/docs/README.md index 4cf18ee74d0..76b46c7d061 100644 --- a/cuda_python/docs/README.md +++ b/cuda_python/docs/README.md @@ -4,7 +4,11 @@ 2. Build the docs with `./build_docs.sh`. 3. The html artifacts should be available under both `./build/html/latest` and `./build/html/`. -Alternatively, we can build all the docs at once by running [`./build_all_docs.sh`](./build_all_docs.sh). +[`./build_all_docs.sh`](./build_all_docs.sh) builds the metapackage, current +CUDA 13 bindings, Core, and Pathfinder documentation together. It does not +build the [CUDA 12 maintenance documentation](../../cuda_bindings_12/docs/README.md). +Build that separately in its own environment: both bindings roots install the +same `cuda-bindings` distribution and `cuda.bindings` namespace. When building the docs, some (but not all) of the urls can be rendered/examined locally by setting the environment variable `CUDA_PYTHON_DOMAIN` as follows: From 537a06e0f5a60605165f439c23e7fc1fb07a0668 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 14:32:04 -0700 Subject: [PATCH 13/19] Describe artifact retention as workflow-specific Signed-off-by: Ralf W. Grosse-Kunstleve --- CONTRIBUTING.md | 2 +- ci/ci-pipeline.mmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 192d7d5845d..759545c5e79 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -462,7 +462,7 @@ for package/major names, local versus published bindings, and reuse details. - **Self-hosted runners**: Used for Linux builds and GPU testing (more resources, faster builds) - **GitHub-hosted runners**: Used for Windows builds and general tasks -- **Artifact retention**: 30 days for GitHub Artifacts (wheels, docs, tests) +- **Artifact retention**: Set per workflow for wheels, documentation, and test results - **Cache retention**: GitHub Cache for build dependencies and environments - **Security**: All commits must be signed, untrusted code blocked - **Parallel execution**: Matrix builds across Python versions and platforms diff --git a/ci/ci-pipeline.mmd b/ci/ci-pipeline.mmd index 6dcce24e4f9..a9c9abab092 100644 --- a/ci/ci-pipeline.mmd +++ b/ci/ci-pipeline.mmd @@ -42,7 +42,7 @@ flowchart TB subgraph ARTIFACTS["ARTIFACT STORAGE"] direction TB subgraph GITHUB_ARTIFACTS["GitHub Artifacts"] - GA1["Wheel files (.whl)
Test artifacts
Documentation
(30-day retention)"] + GA1["Wheel files (.whl)
Test artifacts
Documentation
(Workflow-specific retention)"] end subgraph GITHUB_CACHE["GitHub Cache"] GC1["Mini CTK cache"] From 61dd9323c6df8ec60eae32ff43cf711f8033fa18 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 17:15:58 -0700 Subject: [PATCH 14/19] Prepare maintenance versions before Pixi GPU source tests Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/ci-pixi-source-test.yml | 24 ++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index fd401b01b87..48a471d980a 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -345,10 +345,11 @@ jobs: run: | apt-get update # ca-certificates + git for checkout; libgl1/libegl1 for pyglet - # (pulled in by the test env). PyYAML and packaging drive the - # bindings registry resolver; pixi itself is installed by setup-pixi. + # (pulled in by the test env). Python packages support the bindings + # registry and maintenance SCM preparation; setup-pixi installs pixi. apt-get install -y --no-install-recommends \ - ca-certificates git jq libgl1 libegl1 python3 python3-packaging python3-yaml + ca-certificates git jq libgl1 libegl1 python3 \ + python3-packaging python3-setuptools-scm python3-yaml - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -361,22 +362,27 @@ jobs: # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true - - name: Select CUDA environment + - name: Prepare selected CUDA environment env: REQUESTED_CUDA_ENV: ${{ inputs.cuda-env || '' }} run: | if [[ -n "${REQUESTED_CUDA_ENV}" ]]; then bindings_packages=$(python3 -m ci.tools.bindings_config --package-roots) - if ! jq -e --arg cuda_env "${REQUESTED_CUDA_ENV}" \ - 'any(.[]; .cuda_variant == $cuda_env)' <<< "${bindings_packages}" > /dev/null; then + bindings_package=$(jq -c --arg cuda_env "${REQUESTED_CUDA_ENV}" \ + '.[] | select(.cuda_variant == $cuda_env)' <<< "${bindings_packages}") + if [[ -z "${bindings_package}" ]]; then registered_envs=$(jq -r '[.[].cuda_variant] | join(", ")' <<< "${bindings_packages}") echo "::error::cuda-env must be a registered pixi environment: ${registered_envs}" exit 1 fi - cuda_env="${REQUESTED_CUDA_ENV}" else - current_package=$(python3 -m ci.tools.bindings_config --release-status current) - cuda_env=$(jq -r '.cuda_variant' <<< "${current_package}") + bindings_package=$(python3 -m ci.tools.bindings_config --release-status current) + fi + cuda_env=$(jq -r '.cuda_variant' <<< "${bindings_package}") + if [[ $(jq -r '.release_status' <<< "${bindings_package}") == maintenance ]]; then + bindings_root=$(jq -r '.package_root' <<< "${bindings_package}") + # Match build-smoke's version preparation before any pixi source build. + python3 -m ci.tools.bindings_scm_version --package-root "${bindings_root}" --sha "$GITHUB_SHA" fi echo "CUDA_ENV=${cuda_env}" | tee -a "$GITHUB_ENV" From 3f7ebc286d836a32ef7f8b6df72d122a0b7539f5 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 17:16:03 -0700 Subject: [PATCH 15/19] Explain compatible nightly sources and historical release reruns Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/ci-nightly.yml | 7 +++-- ci/README.md | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index ebc4170ecda..bba447b8adf 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -121,8 +121,11 @@ jobs: snapshot=$(mktemp -d) trap 'rm -rf -- "$snapshot"' EXIT git archive "$HEAD_SHA" | tar -x -C "$snapshot" - BINDINGS_CONFIG=$(python -m ci.tools.bindings_config \ - --config "$snapshot/ci/versions.yml") + if ! BINDINGS_CONFIG=$(python -m ci.tools.bindings_config \ + --config "$snapshot/ci/versions.yml"); then + echo "::error::CI run $RUN_ID ($HEAD_SHA) has no bindings registry compatible with this nightly workflow. Wait for a successful main CI run with the current registry, or dispatch ci-nightly.yml with a compatible run-id. See ci/README.md#nightly-artifact-sources-and-rollout." + exit 1 + fi echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT echo "head_sha=$HEAD_SHA" >> $GITHUB_OUTPUT diff --git a/ci/README.md b/ci/README.md index 4bd4bb12429..bb313fcc895 100644 --- a/ci/README.md +++ b/ci/README.md @@ -336,6 +336,33 @@ automatically establish milestones for the current-major root. Use the same local-preview safeguards while preparing the new source and confirm the resolved version and `git describe` output before retaining its milestone. +## Nightly Artifact Sources And Rollout + +`ci-nightly.yml` downloads wheels from the latest successful main CI run and +reads the bindings registry from that run's source commit. The source registry +must be compatible with the nightly workflow; the current workflow requires +schema 2. It does not translate an older registry into the new layout. + +After multi-root CI lands on `main`, wait for the first successful, complete +main CI run containing the new registry and both bindings majors before using +it as the nightly artifact source. Until that run succeeds, auto-detection can +still select an older successful run; the nightly job then reports the +incompatible source and stops. PR CI builds and tests everything when it has +no complete, compatible artifact baseline. + +To test the nightly workflow before that main run is available, supply the ID +of a successful CI run built with the compatible registry and required wheel +artifacts, such as a validated PR run: + +```console +gh workflow run ci-nightly.yml --repo NVIDIA/cuda-python --ref main -f 'run-id=' +``` + +The override selects both the wheel artifacts and their source revision. It +does not convert old artifacts or change the default selection for later +nightly runs. Once a compatible main run succeeds, ordinary nightly dispatches +can leave `run-id` empty. + ## Reading CI Jobs and Summaries A name such as `pathfinder+bindings12+core12+meta12 / py3.11, CTK12.9.1 @@ -375,3 +402,30 @@ coverage rules after each platform reads its source matrix and applies an optional jq filter. Matrix data comes from the artifact source revision; the helper comes from the workflow control revision so older artifact sources do not need to contain newly introduced CI tooling. + +## Historical Release And Documentation Reruns + +Current release and documentation workflows read package paths and toolkit +settings from the schema-2 registry committed with the release tag. For tags +that predate that registry, dispatch compatible historical tooling instead. +In particular, CUDA 13.4 releases from `13.4.x` use the release workflow on +that branch, including when rebuilding their documentation. + +For example, validate the existing `v13.4.4` release and rebuild its docs with: + +```console +gh workflow run release.yml --repo NVIDIA/cuda-python --ref 13.4.x \ + -f component=cuda-bindings -f release-action=dry-run \ + -f git-tag=v13.4.4 -f 'backport-git-tag=not planned' +``` + +Here `--ref 13.4.x` selects the workflow and its reusable documentation +workflow; `git-tag` selects the immutable release source. Leave `run-id` empty +to find that tag's successful CI run, or supply its validated artifact run ID +if needed. The artifacts must still exist. A dry run validates artifacts and +builds docs without publishing a release; its documentation is retained as a +workflow artifact. Optionally add `-f dry-run-docs-branch=gh-pages-dry-run` to +deploy the documentation to that preview branch. Run once per component when +validating more than one package; use `component=cuda-python` for the matching +metapackage documentation. Other historical release lines likewise need +tooling compatible with their tagged layout. From b90659e97711ce0cdb7df3754e9d0efb2076f106 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 17:17:38 -0700 Subject: [PATCH 16/19] Serialize the matching CUDA 12 global coredump test Signed-off-by: Ralf W. Grosse-Kunstleve --- cuda_bindings_12/tests/test_cuda.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cuda_bindings_12/tests/test_cuda.py b/cuda_bindings_12/tests/test_cuda.py index 402f4eb9a5a..8a5e9bff9cb 100644 --- a/cuda_bindings_12/tests/test_cuda.py +++ b/cuda_bindings_12/tests/test_cuda.py @@ -637,6 +637,7 @@ def test_cuda_graphMem_attr(xfail_on_graph_mempool_oom): or not supportsCudaAPI("cuCoredumpGetAttributeGlobal"), reason="Coredump API not present", ) +@pytest.mark.thread_unsafe(reason="coredump settings are process-global") def test_cuda_coredump_attr(): (err,) = cuda.cuInit(0) assert err == cuda.CUresult.CUDA_SUCCESS From 1574d58930334bd10670d593f4b387d7a5b7395c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Oct 2026 17:20:20 -0700 Subject: [PATCH 17/19] Record the CUDA 12 driver documentation correction Signed-off-by: Ralf W. Grosse-Kunstleve --- cuda_bindings_12/docs/source/release/12.X.Y-notes.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cuda_bindings_12/docs/source/release/12.X.Y-notes.rst b/cuda_bindings_12/docs/source/release/12.X.Y-notes.rst index 7ec6c5f780d..ba49ac922e1 100644 --- a/cuda_bindings_12/docs/source/release/12.X.Y-notes.rst +++ b/cuda_bindings_12/docs/source/release/12.X.Y-notes.rst @@ -24,3 +24,11 @@ Packaging declarations and includes (``.pxd`` and ``.pxi``), together with required headers, remain available for downstream Cython builds. Source distributions retain the sources, templates, and other inputs needed to build the package. + +Documentation +------------- + +* Corrected the CUDA 12 driver guidance to its existing minor-version + compatibility baseline: Linux 525.60.13 and Windows 528.33. This is a + documentation correction, not a new runtime version check. Newer features + and PTX compilation can still require a newer driver. From c8c9578130779695471b3672568ce3b5d7dca769 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 29 Oct 2026 20:05:46 -0700 Subject: [PATCH 18/19] Harden CI tooling across docs and source workflows codex on behalf of Ralf: Use verified workflow-owned Python for registry, nightly, coverage and Pixi helpers. Preserve hardened interpreter PATH in early documentation bootstrap shells and keep historical sources separate from control tools. Signed-off-by: Ralf W. Grosse-Kunstleve --- .github/workflows/build-docs.yml | 11 +++++---- .github/workflows/ci-nightly.yml | 6 +++-- .github/workflows/ci-pixi-source-test.yml | 28 ++++++++++++++--------- .github/workflows/coverage.yml | 6 ++--- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 75494e614c5..38a2b53b00a 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -78,16 +78,19 @@ jobs: ref: ${{ github.sha }} path: .ci-control - - name: Harden pip + - name: Set up Python for CI tools # The release checkout can predate this action; use the workflow revision. - uses: ./.ci-control/.github/actions/harden-pip + uses: ./.ci-control/.github/actions/setup-hardened-python with: - python: python3 + python-version: "3.12" - name: Install CI tool dependencies + # Keep the hardened interpreter ahead of any login-shell activation. + shell: bash --noprofile --norc -euo pipefail {0} run: python3 -m pip install -e ./.ci-control/ci - name: Resolve CUDA bindings package + shell: bash --noprofile --norc -euo pipefail {0} env: BINDINGS_PACKAGE: ${{ inputs.bindings-package }} IS_RELEASE: ${{ inputs.is-release }} @@ -353,7 +356,7 @@ jobs: # interpreter instead of the conda environment used above. - name: Set up Python for link checks if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }} - uses: ./.github/actions/setup-hardened-python + uses: ./.ci-control/.github/actions/setup-hardened-python with: python-version: "3.14" diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index bba447b8adf..cfb9c3c3cd1 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -82,8 +82,10 @@ jobs: with: fetch-depth: 1 - - name: Harden pip - uses: ./.github/actions/harden-pip + - name: Set up Python + uses: ./.github/actions/setup-hardened-python + with: + python-version: "3.12" - name: Install CI tool dependencies run: python -m pip install -e ./ci diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index 48a471d980a..4c3a06887af 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -95,10 +95,10 @@ jobs: # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true - - name: Harden pip - uses: ./.github/actions/harden-pip + - name: Set up Python + uses: ./.github/actions/setup-hardened-python with: - python: python3 + python-version: "3.12" - name: Install CI tool dependencies run: python3 -m pip install -e ./ci @@ -277,10 +277,10 @@ jobs: # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true - - name: Harden pip - uses: ./.github/actions/harden-pip + - name: Set up Python + uses: ./.github/actions/setup-hardened-python with: - python: python3 + python-version: "3.12" - name: Install CI tool dependencies run: python3 -m pip install -e ./ci @@ -344,12 +344,10 @@ jobs: - name: Install system packages run: | apt-get update - # ca-certificates + git for checkout; libgl1/libegl1 for pyglet - # (pulled in by the test env). Python packages support the bindings - # registry and maintenance SCM preparation; setup-pixi installs pixi. + # ca-certificates + git for checkout; libgl1/libegl1 for pyglet. + # The hardened Python setup below supplies the CI helper interpreter. apt-get install -y --no-install-recommends \ - ca-certificates git jq libgl1 libegl1 python3 \ - python3-packaging python3-setuptools-scm python3-yaml + ca-certificates git jq libgl1 libegl1 - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -362,6 +360,14 @@ jobs: # third_party/cccl provides the CCCL headers cuda.core compiles against. submodules: true + - name: Set up Python + uses: ./.github/actions/setup-hardened-python + with: + python-version: "3.12" + + - name: Install CI tool dependencies + run: python3 -m pip install -e ./ci + - name: Prepare selected CUDA environment env: REQUESTED_CUDA_ENV: ${{ inputs.cuda-env || '' }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 2324b914f19..c46f5fe9be9 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,10 +25,10 @@ jobs: steps: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Harden pip - uses: ./.github/actions/harden-pip + - name: Set up Python + uses: ./.github/actions/setup-hardened-python with: - python: python3 + python-version: "3.12" - name: Install CI tool dependencies run: python3 -m pip install -e ./ci From 34664b270a324b5fa7d401d52c964ecf7ea1b84a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 29 Oct 2026 20:12:08 -0700 Subject: [PATCH 19/19] Qualify historical CI sources with current security prerequisites codex on behalf of Ralf: Require checksum-bearing driver matrices for nightly source overrides and current control-workflow security fixes before dispatching historical release tooling. Keep immutable release sources and fail-closed verification unchanged. Signed-off-by: Ralf W. Grosse-Kunstleve --- ci/README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ci/README.md b/ci/README.md index bb313fcc895..67f6c4cb297 100644 --- a/ci/README.md +++ b/ci/README.md @@ -342,6 +342,11 @@ resolved version and `git describe` output before retaining its milestone. reads the bindings registry from that run's source commit. The source registry must be compatible with the nightly workflow; the current workflow requires schema 2. It does not translate an older registry into the new layout. +Selected rows that install a custom driver must also include its +`DRIVER_SHA256` in the source matrix. Registry compatibility alone does not +make a pre-hardening source compatible: choose a newer successful run rather +than disabling installer verification. Rows using preinstalled drivers do not +need an installer checksum. After multi-root CI lands on `main`, wait for the first successful, complete main CI run containing the new registry and both bindings majors before using @@ -351,8 +356,8 @@ incompatible source and stops. PR CI builds and tests everything when it has no complete, compatible artifact baseline. To test the nightly workflow before that main run is available, supply the ID -of a successful CI run built with the compatible registry and required wheel -artifacts, such as a validated PR run: +of a successful CI run built with the compatible registry, required wheel +artifacts, and driver-checksum metadata, such as a validated PR run: ```console gh workflow run ci-nightly.yml --repo NVIDIA/cuda-python --ref main -f 'run-id=' @@ -411,7 +416,14 @@ that predate that registry, dispatch compatible historical tooling instead. In particular, CUDA 13.4 releases from `13.4.x` use the release workflow on that branch, including when rebuilding their documentation. -For example, validate the existing `v13.4.4` release and rebuild its docs with: +Before dispatching historical tooling, bring its control branch up to date +with the applicable CI security fixes, including a verified patched Python +and current CA/download protections. Source-layout compatibility alone is +insufficient. The example below assumes those safeguards are in place; it +does not require changing the immutable release source. + +After meeting that prerequisite, validate the existing `v13.4.4` release and +rebuild its docs with: ```console gh workflow run release.yml --repo NVIDIA/cuda-python --ref 13.4.x \