Add free-threaded Python support #4263
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Test | |
on: | |
pull_request: | |
paths-ignore: | |
- "guide/**" | |
- "sysconfig/**" | |
- "**.md" | |
- ".cirrus.yml" | |
- ".github/ISSUE_TEMPLATE/**" | |
- ".github/dependabot.yml" | |
workflow_dispatch: | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number }} | |
cancel-in-progress: true | |
jobs: | |
lint: | |
name: Lint | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- run: | | |
rustup component add rustfmt | |
rustup component add clippy | |
- name: cargo fmt | |
run: cargo fmt --all -- --check | |
- uses: EmbarkStudios/cargo-deny-action@v2 | |
with: | |
arguments: --all-features | |
- name: cargo clippy | |
run: cargo clippy --tests --all-features -- -D warnings | |
test: | |
name: Test | |
strategy: | |
fail-fast: false | |
matrix: | |
os: | |
- ubuntu-latest | |
- macos-13 | |
- macos-14 | |
- windows-latest | |
python-version: | |
- '3.9' | |
- '3.13' | |
- 'pypy3.10' | |
exclude: | |
# Skip PyPy on macOS M1 runner because they are built for x86_64 | |
- os: macos-14 | |
python-version: pypy3.10 | |
# TODO: Tests are getting stuck | |
- os: ubuntu-latest | |
python-version: pypy3.10 | |
# macOS M1 runner only have Python 3.11+ | |
- os: macos-14 | |
python-version: 3.9 | |
runs-on: ${{ matrix.os }} | |
env: | |
RUST_BACKTRACE: "1" | |
SCCACHE_GHA_ENABLED: "true" | |
RUSTC_WRAPPER: "sccache" | |
steps: | |
- name: Enable long paths | |
if: startsWith(matrix.os, 'windows') | |
run: | | |
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f | |
- name: Cleanup Disk | |
if: ${{ !startsWith(matrix.os, 'windows') }} | |
run: | | |
sudo rm -rf /usr/share/dotnet | |
sudo rm -rf /opt/ghc | |
- name: Sccache Setup | |
uses: mozilla-actions/[email protected] | |
with: | |
version: "v0.7.6" | |
- uses: actions/checkout@v4 | |
- uses: conda-incubator/setup-miniconda@v3 | |
with: | |
auto-activate-base: "false" | |
activate-environment: "" | |
miniconda-version: "latest" | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
- name: Set PYTHON_VERSION env var | |
shell: bash | |
run: | | |
set -ex | |
# remove -dev suffix | |
python_version=$(echo ${{ matrix.python-version }} | sed -e s/-dev//) | |
echo "PYTHON_VERSION=$python_version" >> "${GITHUB_ENV}" | |
- uses: astral-sh/setup-uv@v3 | |
- name: Install python packages | |
run: | | |
uv tool install virtualenv | |
uv tool install twine | |
uv pip install --system "ziglang>=0.10.0,<0.13.0" uniffi-bindgen==0.28.0 | |
- uses: dtolnay/rust-toolchain@stable | |
id: rustup | |
with: | |
targets: wasm32-wasi # Used by the test suite | |
- name: Install cargo-nextest | |
uses: taiki-e/install-action@nextest | |
- name: Install additional Rust target | |
if: startsWith(matrix.os, 'macos') | |
run: rustup target add aarch64-apple-darwin x86_64-apple-darwin | |
- name: Setup Xcode env | |
if: startsWith(matrix.os, 'macos') | |
shell: bash | |
run: | | |
set -ex | |
sudo xcode-select -s /Applications/Xcode.app | |
bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin" | |
echo "CC=${bindir}/clang" >> "${GITHUB_ENV}" | |
echo "CXX=${bindir}/clang++" >> "${GITHUB_ENV}" | |
echo "SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" >> "${GITHUB_ENV}" | |
# Caching | |
- name: Set MATURIN_TEST_PYTHON for PyPy | |
shell: bash | |
if: contains(matrix.python-version, 'pypy') | |
run: echo "MATURIN_TEST_PYTHON=pypy3" >> $GITHUB_ENV | |
# To save disk space | |
- name: Disable debuginfo on Windows | |
if: startsWith(matrix.os, 'windows') | |
run: echo "RUSTFLAGS="-C debuginfo=0"" >> $GITHUB_ENV | |
- name: cargo test | |
run: cargo nextest run --features password-storage | |
# TODO: https://github.com/PyO3/maturin/issues/2263 | |
#- name: test cross compiling with zig | |
# if: ${{ !contains(matrix.python-version, '-dev') }} | |
# shell: bash | |
# run: | | |
# set -ex | |
# rustup target add aarch64-unknown-linux-gnu | |
# rustup target add aarch64-unknown-linux-musl | |
# rustup target add aarch64-apple-darwin | |
# | |
# # abi3 | |
# cargo run build -i $PYTHON_VERSION -m test-crates/pyo3-pure/Cargo.toml --target aarch64-unknown-linux-gnu --zig | |
# cargo run build -i $PYTHON_VERSION -m test-crates/pyo3-pure/Cargo.toml --target aarch64-unknown-linux-musl --zig | |
# if [[ "$PYTHON_VERSION" != "pypy"* ]]; then | |
# cargo run build -i $PYTHON_VERSION -m test-crates/pyo3-pure/Cargo.toml --target aarch64-apple-darwin --zig | |
# fi | |
# | |
# if [[ "$PYTHON_VERSION" == "3.1"* ]]; then | |
# # Check abi3 wheels with abi3audit on CPython only | |
# pip install abi3audit | |
# abi3audit test-crates/pyo3-pure/target/wheels/*.whl | |
# fi | |
# # Check wheels with twine | |
# twine check --strict test-crates/pyo3-pure/target/wheels/*.whl | |
# | |
# # non-abi3 | |
# cargo run build -i $PYTHON_VERSION -m test-crates/pyo3-mixed/Cargo.toml --target aarch64-unknown-linux-gnu --zig | |
# if [[ "$PYTHON_VERSION" != "pypy"* ]]; then | |
# cargo run build -i $PYTHON_VERSION -m test-crates/pyo3-mixed/Cargo.toml --target aarch64-apple-darwin --zig | |
# fi | |
# # Check wheels with twine | |
# twine check --strict test-crates/pyo3-mixed/target/wheels/*.whl | |
- name: test compiling with PYO3_CONFIG_FILE | |
shell: bash | |
run: | | |
set -ex | |
rustup target add x86_64-unknown-linux-gnu | |
export PYO3_CONFIG_FILE=$(pwd)/test-crates/pyo3-mixed/pyo3-config.txt | |
target/debug/maturin build -m test-crates/pyo3-mixed/Cargo.toml --target x86_64-unknown-linux-gnu --zig | |
- name: test maturin new | |
shell: bash | |
run: | | |
set -ex | |
target/debug/maturin new -b pyo3 test-crates/pyo3-new | |
target/debug/maturin build -m test-crates/pyo3-new/Cargo.toml --target-dir test-crates/targets/ | |
target/debug/maturin new --mixed -b pyo3 test-crates/pyo3-new-mixed | |
target/debug/maturin build -m test-crates/pyo3-new-mixed/Cargo.toml --target-dir test-crates/targets/ | |
build-maturin: | |
name: Build maturin | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- run: rustup show | |
- run: rustup target add x86_64-unknown-linux-musl | |
- run: sudo apt-get install musl-tools | |
- uses: Swatinem/rust-cache@v2 | |
- run: cargo build --target x86_64-unknown-linux-musl | |
- uses: actions/upload-artifact@v4 | |
with: | |
name: maturin-build | |
path: target/x86_64-unknown-linux-musl/debug/maturin | |
test-windows-cross: | |
name: Test windows cross | |
needs: build-maturin | |
runs-on: ubuntu-latest | |
env: | |
RUST_BACKTRACE: "1" | |
SCCACHE_GHA_ENABLED: "true" | |
RUSTC_WRAPPER: "sccache" | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Sccache Setup | |
uses: mozilla-actions/[email protected] | |
with: | |
version: "v0.7.6" | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: 3.12 | |
- uses: actions/download-artifact@v4 | |
with: | |
name: maturin-build | |
path: bin | |
- run: chmod +x bin/maturin | |
- name: test cross compiling windows wheel | |
run: | | |
set -ex | |
sudo apt-get install -y mingw-w64 | |
rustup component add llvm-tools-preview | |
rustup target add x86_64-pc-windows-gnu | |
rustup target add x86_64-pc-windows-msvc | |
# abi3 | |
bin/maturin build -m test-crates/pyo3-pure/Cargo.toml --target x86_64-pc-windows-gnu | |
# TODO: timeout | |
# bin/maturin build -m test-crates/pyo3-pure/Cargo.toml --target x86_64-pc-windows-msvc | |
# no-abi3 | |
# bin/maturin build -i python3.12 -m test-crates/pyo3-mixed/Cargo.toml --target x86_64-pc-windows-msvc | |
test-emscripten: | |
name: Test Emscripten | |
runs-on: ubuntu-latest | |
env: | |
PYODIDE_VERSION: "0.23.4" | |
PYTHON_VERSION: "3.11.2" | |
NODE_VERSION: 18 | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
id: setup-python | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
- uses: dtolnay/rust-toolchain@nightly | |
with: | |
components: rust-src | |
targets: wasm32-unknown-emscripten | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
shared-key: maturin-build | |
- uses: astral-sh/setup-uv@v3 | |
- run: uv tool install nox | |
- name: Setup Pyodide | |
run: nox -s setup-pyodide | |
- uses: mymindstorm/setup-emsdk@v14 | |
with: | |
version: ${{ env.EMSCRIPTEN_VERSION }} | |
actions-cache-folder: emsdk-cache | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
- name: Run tests | |
run: nox -s test-emscripten | |
test-alpine: | |
name: Test Alpine Linux | |
runs-on: ubuntu-latest | |
env: | |
RUST_BACKTRACE: "1" | |
CARGO_INCREMENTAL: "0" | |
CARGO_TERM_COLOR: always | |
container: alpine:latest | |
steps: | |
- name: Install build requirements | |
run: | | |
set -ex | |
apk add cargo python3-dev libffi-dev py3-pip curl \ | |
bash tar zstd git patchelf py3-virtualenv | |
- uses: actions/checkout@v4 | |
- name: Fix git permissions | |
run: git config --global --add safe.directory $GITHUB_WORKSPACE | |
- name: Cache cargo build | |
uses: Swatinem/rust-cache@v2 | |
with: | |
shared-key: maturin-build | |
- name: Install cargo-nextest | |
uses: taiki-e/install-action@nextest | |
- name: cargo test | |
run: | | |
# unset GITHUB_ACTIONS env var to disable zig related tests | |
env -u GITHUB_ACTIONS cargo nextest run --features password-storage | |
test-auditwheel: | |
name: Test Auditwheel | |
needs: build-maturin | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
manylinux: ["manylinux_2_28"] | |
container: quay.io/pypa/${{ matrix.manylinux }}_x86_64 | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dtolnay/rust-toolchain@stable | |
- uses: actions/download-artifact@v4 | |
with: | |
name: maturin-build | |
path: bin | |
- run: chmod +x bin/maturin | |
- name: Compliant Build | |
run: tests/manylinux_compliant.sh bin/maturin ${{ matrix.manylinux }} | |
- name: Incompliant Build | |
if: matrix.manylinux == 'manylinux_2_28' | |
run: tests/manylinux_incompliant.sh bin/maturin | |
test-docker: | |
name: Test Docker | |
runs-on: ubuntu-latest | |
env: | |
CARGO_INCREMENTAL: "0" | |
CARGO_TERM_COLOR: always | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.11" | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- uses: docker/setup-buildx-action@v3 | |
- name: Build | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
push: false | |
tags: maturin | |
load: true | |
cache-from: type=registry,ref=ghcr.io/pyo3/maturin:buildcache | |
- name: Test the Docker container | |
run: ./test-dockerfile.sh | |
test-cross-compile: | |
name: Test Cross Compile | |
needs: build-maturin | |
runs-on: ubuntu-latest | |
container: ${{ matrix.platform.container }} | |
strategy: | |
fail-fast: false | |
matrix: | |
platform: | |
# CPython | |
- target: aarch64-unknown-linux-gnu | |
abi: cp39-cp39 | |
python: python3.9 | |
container: ghcr.io/rust-cross/manylinux2014-cross:aarch64 | |
- target: armv7-unknown-linux-gnueabihf | |
abi: cp39-cp39 | |
python: python3.9 | |
container: ghcr.io/rust-cross/manylinux2014-cross:armv7 | |
- target: s390x-unknown-linux-gnu | |
abi: cp310-cp310 | |
python: python3.10 | |
container: ghcr.io/rust-cross/manylinux2014-cross:s390x | |
# PyPy | |
- target: aarch64-unknown-linux-gnu | |
abi: pp310-pypy310_pp73 | |
python: pypy3.10 | |
container: ghcr.io/rust-cross/manylinux2014-cross:aarch64 | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/download-artifact@v4 | |
with: | |
name: maturin-build | |
path: bin | |
- run: chmod +x bin/maturin | |
- uses: dtolnay/rust-toolchain@stable | |
with: | |
targets: ${{ matrix.platform.target }} | |
- name: Build wheels | |
run: | | |
set -ex | |
# Use bundled sysconfig | |
bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml | |
# Use PYO3_CROSS_LIB_DIR | |
export PYO3_CROSS_LIB_DIR=/opt/python/${{ matrix.platform.abi }} | |
bin/maturin build -i python3.9 --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml | |
unset PYO3_CROSS_LIB_DIR | |
# Test abi3 | |
bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-pure/Cargo.toml | |
# --find-interpreter | |
bin/maturin build --find-interpreter --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml | |
test-bootstrap: | |
name: Test Bootstrap | |
runs-on: ${{ matrix.os }} | |
env: | |
SCCACHE_GHA_ENABLED: "true" | |
RUSTC_WRAPPER: "sccache" | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, macos-14, windows-latest] | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dorny/paths-filter@v3 | |
id: changes | |
with: | |
filters: | | |
changed: | |
- 'maturin/**' | |
- 'pyproject.toml' | |
- 'setup.py' | |
- 'MANIFEST.in' | |
- 'Cargo.toml' | |
- '.github/workflows/test.yml' | |
- uses: astral-sh/setup-uv@v3 | |
# Caching | |
- name: Sccache Setup | |
if: ${{ steps.changes.outputs.changed == 'true' || contains(github.event.pull_request.labels.*.name, 'release') }} | |
uses: mozilla-actions/[email protected] | |
with: | |
version: "v0.7.6" | |
- uses: actions/setup-python@v5 | |
if: ${{ steps.changes.outputs.changed == 'true' || contains(github.event.pull_request.labels.*.name, 'release') }} | |
with: | |
python-version: "3.10" | |
- name: Build and install | |
shell: bash | |
run: | | |
set -ex | |
cargo run sdist -o dist | |
uv pip install --system -v dist/maturin-*.tar.gz | |
if: ${{ steps.changes.outputs.changed == 'true' || contains(github.event.pull_request.labels.*.name, 'release') }} | |
- run: maturin --version | |
if: ${{ steps.changes.outputs.changed == 'true' || contains(github.event.pull_request.labels.*.name, 'release') }} | |
- run: python3 -m maturin --version | |
if: ${{ steps.changes.outputs.changed == 'true' || contains(github.event.pull_request.labels.*.name, 'release') }} | |
- name: Upload wheel artifacts | |
if: ${{ steps.changes.outputs.changed == 'true' || contains(github.event.pull_request.labels.*.name, 'release') }} | |
uses: actions/upload-artifact@v4 | |
with: | |
name: wheels-${{ runner.os }} | |
path: dist | |
test-msrv: | |
name: Test MSRV | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dtolnay/[email protected] | |
# Caching | |
- name: Cache cargo build | |
uses: Swatinem/rust-cache@v2 | |
- run: cargo build --no-default-features | |
- name: cargo build | |
run: cargo build --all | |
test-downstream: | |
name: Test downstream - ${{ matrix.downstream.repository }} | |
if: ${{ contains(github.event.pull_request.labels.*.name, 'sdist') && github.event_name == 'pull_request' }} | |
uses: ./.github/workflows/downstream.yml | |
with: | |
repository: ${{ matrix.downstream.repository }} | |
manifest-dir: ${{ matrix.downstream.manifest-dir }} | |
strategy: | |
fail-fast: false | |
matrix: | |
downstream: | |
- repository: "pola-rs/polars" | |
manifest-dir: "py-polars" | |
- repository: "astral-sh/ruff" | |
manifest-dir: "crates/ruff_cli" | |
- repository: "crate-ci/typos" | |
manifest-dir: "crates/typos-cli" | |
- repository: "ast-grep/ast-grep" | |
manifest-dir: "crates/pyo3" | |
- repository: "oxigraph/oxigraph" | |
manifest-dir: "python" | |
check: | |
name: Check ${{ matrix.platform.target }} | |
strategy: | |
fail-fast: false | |
matrix: | |
platform: | |
- target: armv5te-unknown-linux-gnueabi | |
apt-packages: gcc-arm-linux-gnueabi | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Install packages | |
run: | | |
sudo apt-get update | |
sudo apt-get install -y ${{ matrix.platform.apt-packages }} | |
- run: rustup target add ${{ matrix.platform.target }} | |
- name: Cache cargo build | |
uses: Swatinem/rust-cache@v2 | |
- name: cargo check | |
run: cargo check --target ${{ matrix.platform.target }} | |
conclusion: | |
needs: | |
- test | |
- test-emscripten | |
- test-alpine | |
- test-auditwheel | |
- test-docker | |
- test-cross-compile | |
- test-bootstrap | |
- test-msrv | |
- test-downstream | |
- check | |
runs-on: ubuntu-latest | |
steps: | |
- name: Result | |
run: | | |
jq -C <<< "${needs}" | |
# Check if all needs were successful or skipped. | |
"$(jq -r 'all(.result as $result | (["success", "skipped"] | contains([$result])))' <<< "${needs}")" | |
env: | |
needs: ${{ toJson(needs) }} |