name: Python Bindings CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
release:
types: [ published ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name != 'release' }}
env:
CARGO_TERM_COLOR: always
jobs:
test:
name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo registry
uses: actions/cache@v5
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache Cargo index
uses: actions/cache@v5
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache Cargo build
uses: actions/cache@v5
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Create virtual environment with uv
run: uv venv
- name: Install maturin
run: uv pip install maturin pytest
- name: Build Python wheel
run: uv run maturin build --release --features python --out dist
- name: Install built wheel
shell: bash
run: |
wheel=$(ls dist/*.whl)
uv run pip install "$wheel"
- name: Run Rust tests with Python feature
if: runner.os != 'macOS'
run: cargo test --lib --tests --features python
- name: Run Python tests
run: uv run pytest tests/test_python.py -v
lint:
name: Lint and Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Check formatting
run: cargo fmt --check
- name: Run Clippy with Python feature
run: cargo clippy --features python --all-targets --workspace -- -D warnings
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Pin Python version
run: uv python pin 3.11
- name: Install dependencies
run: uv sync --group dev
- name: Generate .pyi from Rust
run: uvx rylai -o python/pdf_oxide/
- name: Run Ruff
run: uv run ruff check . --fix
- name: Run ty check
run: uv run ty check .
build-wheels-linux:
name: Build wheels (linux ${{ matrix.target }} ${{ matrix.manylinux }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- target: x86_64
manylinux: manylinux_2_28
- target: aarch64
manylinux: manylinux_2_28
- target: x86_64
manylinux: musllinux_1_2
- target: aarch64
manylinux: musllinux_1_2
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: ${{ matrix.manylinux }}
args: --release --features python --out dist
- name: Upload wheels as artifacts
uses: actions/upload-artifact@v7
with:
name: wheels-linux-${{ matrix.target }}-${{ matrix.manylinux }}
path: dist/*.whl
build-wheels-macos:
name: Build wheels (macos ${{ matrix.target }})
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --features python --out dist
- name: Upload wheels as artifacts
uses: actions/upload-artifact@v7
with:
name: wheels-macos-${{ matrix.target }}
path: dist/*.whl
build-wheels-windows:
name: Build wheels (windows ${{ matrix.target }})
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
target: [x64, aarch64]
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
architecture: x64
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --features python --out dist
- name: Upload wheels as artifacts
uses: actions/upload-artifact@v7
with:
name: wheels-windows-${{ matrix.target }}
path: dist/*.whl
build-sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- name: Upload sdist as artifact
uses: actions/upload-artifact@v7
with:
name: sdist
path: dist/*.tar.gz
publish:
name: Publish to PyPI
needs: [test, lint, build-wheels-linux, build-wheels-macos, build-wheels-windows, build-sdist]
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/download-artifact@v8
with:
pattern: wheels-*
path: dist
merge-multiple: true
- uses: actions/download-artifact@v8
with:
name: sdist
path: dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
skip-existing: true
docs:
name: Generate Python documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
pip install maturin pdoc3
- name: Build and install wheel
shell: bash
run: |
maturin build --release --features python --out dist
wheel=$(ls dist/*.whl)
pip install "$wheel"
- name: Generate docs
run: pdoc --html --output-dir docs-python pdf_oxide
- name: Upload docs
uses: actions/upload-artifact@v7
with:
name: python-docs
path: docs-python/