From 8f36152ac907b2379abe7c6094f2304d623eff17 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 13 Oct 2026 11:52:17 +0000 Subject: [PATCH 1/2] Add riscv64 build for pyvrp 0.14.0 MIT-licensed meson/pybind11 C++ VRP solver. No SIMD/-march gates found in meson.build or sources; mirrors upstream CD.yml's plain cibuildwheel build (CIBW_PLATFORM: auto). Matches upstream's own cp311-cp314 build glob (no cp314t); numpy/matplotlib and matplotlib's compiled deps are already on the registry for all four interpreters. --- .github/workflows/build-pyvrp.yml | 113 ++++++++++++++++++++++++++++++ docs/packages/pyvrp.yaml | 5 ++ 2 files changed, 118 insertions(+) create mode 100644 .github/workflows/build-pyvrp.yml create mode 100644 docs/packages/pyvrp.yaml diff --git a/.github/workflows/build-pyvrp.yml b/.github/workflows/build-pyvrp.yml new file mode 100644 index 000000000000..f4f675b70556 --- /dev/null +++ b/.github/workflows/build-pyvrp.yml @@ -0,0 +1,113 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `build` job of +# https://github.com/PyVRP/PyVRP/blob/v0.14.0/.github/workflows/CD.yml +name: Build pyvrp wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/pyvrp.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-pyvrp.yml' + - 'docs/packages/pyvrp.yaml' + - 'patches/pyvrp/**' + push: + branches: [main] + paths: + - '.github/workflows/build-pyvrp.yml' + - 'docs/packages/pyvrp.yaml' + - 'patches/pyvrp/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: pyvrp + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build pyvrp ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 180 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + # Matches upstream's own cibuildwheel build glob (pyproject.toml), which + # excludes cp314t too. + python: ["cp311", "cp312", "cp313", "cp314"] + + env: + PYVRP_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout PyVRP v${{ env.PYVRP_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: PyVRP/PyVRP + ref: v${{ env.PYVRP_VERSION }} + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch pyvrp source + run: | + patches="python-wheels/patches/pyvrp/${{ env.PYVRP_VERSION }}" + if [ -d "$patches" ]; then + git apply "$patches"/*.patch + fi + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + only: ${{ matrix.python }}-manylinux_riscv64 + env: + CIBW_BUILD_FRONTEND: build + CIBW_ENVIRONMENT: >- + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + PIP_ONLY_BINARY=numpy,matplotlib,contourpy,kiwisolver,pillow + CIBW_TEST_REQUIRES: pytest pytest-cov pytest-xdist + CIBW_TEST_COMMAND: cd {project}/tests && pytest -v + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pyvrp-${{ env.PYVRP_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: ./wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish pyvrp ${{ matrix.version }} + needs: [setup, build_wheels] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + secrets: + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} + with: + artifact-pattern: pyvrp-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/pyvrp.yaml b/docs/packages/pyvrp.yaml new file mode 100644 index 000000000000..9ed48cbcfbee --- /dev/null +++ b/docs/packages/pyvrp.yaml @@ -0,0 +1,5 @@ +package-name: pyvrp +source-code: https://github.com/PyVRP/PyVRP +license: MIT +versions: +- version: 0.14.0 From 08cb2f2cd07feb481c2a929a61c89303cadeeed8 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 23 Oct 2026 16:04:15 +0000 Subject: [PATCH 2/2] pyvrp: deselect matplotlib-3.11 baseline images on cp311 and 10 ms timing tests cp311 resolves matplotlib 3.10.9 (no 3.11 cp311 riscv64 wheel on our index), but upstream regenerated its baseline images with matplotlib 3.11.0, so five image comparisons exceed tol=8.5 there. test_before_max_runtime[0.01] requires 100 stop() calls inside 10 ms under coverage and xdist, which the busy riscv64 runner overshoots. --- .github/workflows/build-pyvrp.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-pyvrp.yml b/.github/workflows/build-pyvrp.yml index f4f675b70556..6c4b4542ba61 100644 --- a/.github/workflows/build-pyvrp.yml +++ b/.github/workflows/build-pyvrp.yml @@ -52,6 +52,17 @@ jobs: # Matches upstream's own cibuildwheel build glob (pyproject.toml), which # excludes cp314t too. python: ["cp311", "cp312", "cp313", "cp314"] + include: + # Upstream's baseline images were regenerated with matplotlib 3.11, + # which has no cp311 riscv64 wheel on our index; 3.10 renders these + # outside tol=8.5. + - python: cp311 + pytest-args: >- + --deselect "tests/plotting/test_plotting.py::test_plot_solution[png]" + --deselect "tests/plotting/test_plotting.py::test_plot_result[png]" + --deselect "tests/plotting/test_plotting.py::test_plot_route_schedule[png]" + --deselect "tests/plotting/test_plotting.py::test_plot_route_schedule_shipments[png]" + --deselect "tests/plotting/test_plotting.py::test_plot_coordinates_shipments[png]" env: PYVRP_VERSION: ${{ matrix.version }} @@ -87,7 +98,13 @@ jobs: PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ PIP_ONLY_BINARY=numpy,matplotlib,contourpy,kiwisolver,pillow CIBW_TEST_REQUIRES: pytest pytest-cov pytest-xdist - CIBW_TEST_COMMAND: cd {project}/tests && pytest -v + # 100 calls must finish inside a 10 ms MaxRuntime budget under + # coverage tracing and xdist; the busy riscv64 runner overshoots it. + CIBW_TEST_COMMAND: >- + cd {project}/tests && pytest -v + --deselect "tests/stop/test_MaxRuntime.py::test_before_max_runtime[0.01]" + --deselect "tests/stop/test_MultipleCriteria.py::test_before_max_runtime[0.01]" + ${{ matrix.pytest-args }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: