Skip to content

docs(readme): drop Rust-implementation framing — describe the library… #71

docs(readme): drop Rust-implementation framing — describe the library…

docs(readme): drop Rust-implementation framing — describe the library… #71

Workflow file for this run

name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
yaml-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '3.x'
- name: Install yamllint
# Major-bound pin (like the uvx tools) so a yamllint 2.x can't add rules
# that red this gate without a deliberate bump.
run: pip install 'yamllint>=1,<2'
- name: Lint YAML
run: yamllint .
lint:
name: ruff
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
# Rust toolchain: needed so `uv sync` can build the PyO3 extension via maturin.
- uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 # stable
with:
toolchain: stable
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
- run: uv run ruff format --check .
- run: uv run ruff check .
typecheck:
name: mypy + stubtest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 # stable
with:
toolchain: stable
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
- run: uv run mypy
# stubtest checks the .pyi against the compiled module at runtime — it catches
# signature drift (params/types/defaults) the AST-based drift guard in
# tests/test_api_surface.py cannot see. The allowlist suppresses only
# irreducible PyO3 / stub-only conventions (see stubtest-allowlist.txt).
# --ignore-disjoint-bases keeps the gate stable across mypy upgrades: the
# dual-base exceptions (e.g. Timeout(ProcessError, TimeoutError)) are PEP 800
# disjoint-base candidates a future mypy could start flagging.
- run: uv run python -m mypy.stubtest processkit --ignore-disjoint-bases --allowlist stubtest-allowlist.txt
rust-lint:
name: rust-lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
# PyO3's build script needs a Python interpreter to resolve its config (even
# for a check-only clippy build, which never links libpython). Pin one
# explicitly rather than relying on the runner image's preinstalled python.
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '3.x'
- uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 # stable
with:
toolchain: stable
components: clippy, rustfmt
- run: cargo fmt --all --check
- run: cargo clippy --all-targets -- -D warnings
test:
# One matrix over (OS × interpreter): the empty `python` entry runs the abi3
# (GIL) build via the project's pinned interpreter; `3.14t` provisions the
# free-threaded CPython (PEP 703) and builds the version-specific (non-abi3)
# extension, exercising the suite with the GIL disabled.
name: test (${{ matrix.os }}, ${{ matrix.python || 'abi3' }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]
python: ['', '3.14t']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 # stable
with:
toolchain: stable
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# `uv run` provisions the interpreter, syncs the env (building the Rust
# extension via `maturin develop`), then runs pytest. The `--python` flag is
# added only for the free-threaded entry.
- run: uv run ${{ matrix.python && format('--python {0} ', matrix.python) }}pytest
build:
name: build (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 # stable
with:
toolchain: stable
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Verify the abi3 wheel (cp310+) builds on every target OS, not just Linux —
# a one-OS build would not catch a Windows/macOS packaging break. A debug
# build (no --release) exercises the same abi3 tag / cdylib link / packaging
# path much faster. The optimized (LTO) wheels are built + smoke-tested by
# cibuildwheel: musl x86_64 here (build-musllinux), and the FULL matrix
# (every OS/arch, incl. Windows/macOS) pre-pivot in the release flow — so a
# release-profile-only break can't reach PyPI, it just surfaces at release.
- run: uv run maturin build --out dist
# The sdist is platform-independent; build it once.
- if: matrix.os == 'ubuntu-latest'
run: uv run maturin sdist --out dist
# Assert the release cibuildwheel selector resolves to exactly the intended
# wheel families per libc — the abi3 GIL wheel (cp310) and the free-threaded
# cp314t wheel, for both manylinux (glibc) and musllinux (musl) — so a
# renamed/dropped/re-skipped identifier surfaces here, not at release. (The
# musllinux wheels are actually built + smoke-tested in the build-musllinux
# job below; this only checks the selector resolves.)
- if: matrix.os == 'ubuntu-latest'
name: Verify cibuildwheel build selector
run: |
ids=$(uvx 'cibuildwheel>=4,<5' --print-build-identifiers --platform linux)
echo "$ids"
for fam in cp310-manylinux cp310-musllinux cp314t-manylinux cp314t-musllinux; do
echo "$ids" | grep -q "^$fam" || { echo "::error::$fam wheel not in cibuildwheel selector"; exit 1; }
done
build-musllinux:
# Actually build + smoke-test the musllinux (Alpine/musl) wheels. This is the
# only thing on a push that exercises the musl Rust toolchain path —
# cibuildwheel otherwise runs only in the dispatch-only release flows, so a
# musl-specific break (the before-all hook, maturin's cdylib crt-static
# handling) would otherwise surface only at release. Builds both wheel families
# for x86_64 in the Alpine container (Rust is installed inside it by the
# before-all hook in pyproject.toml — no host toolchain needed); aarch64 musl
# builds natively at release on the ubuntu-24.04-arm runner.
name: build (musllinux x86_64)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
- name: Build + smoke-test musllinux wheels
# Pin the exact two families (abi3 GIL + free-threaded). CIBW_BUILD
# OVERRIDES pyproject's build selector, so a wildcard like *-musllinux_x86_64
# would also pull cp311–cp314 (redundant abi3-reuse smoke runs).
env:
CIBW_BUILD: "cp310-musllinux_x86_64 cp314t-musllinux_x86_64"
run: uvx 'cibuildwheel>=4,<5' --platform linux --output-dir wheelhouse
audit:
name: pip-audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Audit the locked dependency tree. Exporting the lockfile (--no-emit-project
# drops the editable binding itself) lets pip-audit scan the deps without
# building the Rust extension — so no rust-toolchain / compile step is needed.
# The project has no runtime deps, so the dev groups ARE the audit surface:
# --all-groups makes that explicit (not reliant on uv's default-includes-dev),
# and --locked pins the scan to the committed uv.lock (failing loudly if stale).
- run: >-
uv export --no-emit-project --all-groups --locked
--format requirements-txt --output-file requirements-audit.txt
- run: uvx 'pip-audit>=2,<3' -r requirements-audit.txt