Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions .github/workflows/build-pyqwest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on the `linux` job of
# https://github.com/curioswitch/pyqwest/blob/v0.10.0/.github/workflows/release.yaml
name: Build pyqwest wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'pyqwest version to build (git tag without the leading v, e.g. 0.10.0)'
required: true
default: '0.10.0'
pull_request:
paths:
- '.github/workflows/build-pyqwest.yml'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '0.10.0' }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
# `inputs.version` is empty on pull_request events; default to 0.10.0 there.
PYQWEST_VERSION: ${{ inputs.version || '0.10.0' }}
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
setup:
uses: $/.github/workflows/_setup.yml

build_wheels:
needs: [setup]
name: Build pyqwest ${{ inputs.version || '0.10.0' }} ${{ matrix.tag }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 360
strategy:
fail-fast: false
matrix:
include:
# pyo3/abi3-py310 is an opt-in feature upstream's own release job adds
# only on top of a `pyo3/extension-module`-only build (its second
# "Build abi3 wheels" step, `-i 3.10 --features pyo3/abi3-py310`);
# nothing in Cargo.toml turns it on by default. Built on cp310 --
# the oldest interpreter the abi3 tag claims -- and re-tested on the
# newer ones via find_compatible_wheel. pyo3 disables abi3 under
# Py_GIL_DISABLED, so the free-threaded build is its own wheel.
- tag: cp310-abi3
build: >-
cp310-manylinux_riscv64 cp311-manylinux_riscv64
cp312-manylinux_riscv64 cp313-manylinux_riscv64
cp314-manylinux_riscv64
features: --features pyo3/extension-module --features pyo3/abi3-py310
- tag: cp314t
build: cp314t-manylinux_riscv64
features: --features pyo3/extension-module

steps:
- name: Checkout pyqwest v${{ env.PYQWEST_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: curioswitch/pyqwest
ref: v${{ env.PYQWEST_VERSION }}
persist-credentials: false

- name: Replace tests/conftest.py to drop the pyvoy-based local server
# The real conftest.py imports pyvoy unconditionally to run a local
# Envoy-based test server; pyvoy bundles Envoy and ships no riscv64
# wheel anywhere. This keeps only the client_type fixture (copied
# verbatim) needed by the self-contained subset of tests below --
# none of them open a socket or need a live server.
run: |
cat > tests/conftest.py <<'EOF'
from __future__ import annotations

import pytest


@pytest.fixture(params=["async", "sync", "async_asgi", "sync_wsgi"])
def client_type(request: pytest.FixtureRequest) -> str:
return request.param
EOF

- name: Build wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
output-dir: wheelhouse/
env:
# musllinux is dropped: rustup.rs ships no riscv64 musl toolchain.
CIBW_BUILD: ${{ matrix.build }}
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# pyqwest ships no [tool.cibuildwheel], so the Rust toolchain its
# maturin backend needs is installed in-container here. aws-lc-sys
# (pulled in by reqwest's rustls/http3 stack) ships prebuilt
# riscv64gc bindings, and cmake is already in the manylinux image.
CIBW_BEFORE_ALL_LINUX: >-
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
CIBW_ENVIRONMENT_LINUX: >-
PATH="$PATH:$HOME/.cargo/bin"
MATURIN_PEP517_ARGS="${{ matrix.features }}"
CIBW_TEST_REQUIRES: pytest pytest-asyncio pytest-benchmark
CIBW_TEST_SOURCES: >-
tests/__init__.py tests/_util.py tests/conftest.py
tests/test_common.py tests/test_multipart_encode.py
tests/test_protocol_errors.py tests/test_request.py
tests/test_response.py tests/test_timeout.py
tests/test_validation.py pyproject.toml
# The other test files need the pyvoy local server dropped above;
# this subset is the pyvoy-independent slice of upstream's own
# suite -- request/response/multipart construction, protocol-error
# framing over a raw socket (tests/_util.py's raw_server), TLS
# option validation and the sync timeout context manager.
CIBW_TEST_COMMAND: >-
python -c "import pyqwest._pyqwest as m; assert m.__file__.endswith('.so'), m.__file__"
&& python -m pytest -v
tests/test_common.py tests/test_multipart_encode.py
tests/test_protocol_errors.py tests/test_request.py
tests/test_response.py tests/test_timeout.py
tests/test_validation.py

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pyqwest-${{ env.PYQWEST_VERSION }}-${{ matrix.tag }}-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish pyqwest ${{ inputs.version || '0.10.0' }}
needs: [setup, build_wheels]
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
with:
artifact-pattern: pyqwest-${{ inputs.version || '0.10.0' }}-*-manylinux_riscv64