Skip to content

Add free-threaded Python support #4263

Add free-threaded Python support

Add free-threaded Python support #4263

Workflow file for this run

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) }}