Skip to content
Open
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions .github/workflows/_nox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ jobs:
with:
python-version: ${{ matrix.leg.python }}

# Every session builds the Rust crate from source; cache the cargo build.
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
workspaces: packages/pybamm-rust

- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "latest"
Expand Down
101 changes: 90 additions & 11 deletions .github/workflows/publish_pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,79 @@ on:
permissions: {}

jobs:
build:
build_wheels:
# Monorepo: this workflow publishes ONLY pybamm. Releases are discriminated
# by tag namespace now that pybamm and pybammsolvers share a repository
# (the old `github.repository` guard no longer distinguishes them).
if: startsWith(github.event.release.tag_name, 'pybamm-v')
name: Wheels (${{ matrix.os }} ${{ matrix.arch }})
runs-on: ${{ matrix.os }}
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, arch: x86_64, artifact: wheels_manylinux, crossversion: true }
- { os: ubuntu-24.04-arm, arch: aarch64, artifact: wheels_manylinux_aarch64 }
- { os: macos-latest, arch: arm64, artifact: wheels_macos_arm64, deployment_target: "11.0" }
- { os: macos-15-intel, arch: x86_64, artifact: wheels_macos_x86_64, deployment_target: "10.13" }
- { os: windows-2025, arch: AMD64, artifact: wheels_windows }

steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
# Full history + tags so hatch-vcs can resolve the pybamm-v* version.
fetch-depth: 0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: 3.13

# Deliberately no cargo cache here: a cache entry poisoned from a PR could
# be restored into a wheel that gets published. Release builds start clean.
- name: Build wheels
# Pinned: cibuildwheel's abi3audit default is load-bearing here.
run: pipx run cibuildwheel==4.1.1 packages/pybamm --output-dir wheelhouse
env:
CIBW_BUILD_VERBOSITY: 1
# One abi3 wheel per platform serves CPython 3.10-3.14.
CIBW_BUILD: "cp310-*"
CIBW_SKIP: "pp* *musllinux* *t-*"
CIBW_ARCHS: ${{ matrix.arch }}
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment_target }}
# manylinux containers have no rustup; the crate graph needs cargo >= 1.89.
CIBW_BEFORE_ALL_LINUX: >
curl -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
CIBW_ENVIRONMENT_LINUX: 'PATH=$HOME/.cargo/bin:$PATH'
CIBW_TEST_COMMAND: >
python -c "import pybamm; from pybamm.rust import ExprGraph; print(pybamm.__version__, ExprGraph.__module__)"

- name: Check wheel metadata
run: pipx run twine check --strict wheelhouse/*.whl

- name: Verify the abi3 wheel imports on the newest Python
# CIBW_TEST_COMMAND only exercises the build interpreter (3.10). The point
# of abi3 is that the same wheel serves 3.14, so prove it once.
if: ${{ matrix.crossversion }}
run: |
pipx run --spec 'uv' uv venv --python 3.14 /tmp/abi3-check
VIRTUAL_ENV=/tmp/abi3-check pipx run --spec 'uv' uv pip install wheelhouse/*.whl
/tmp/abi3-check/bin/python -c "
import sys
from pybamm.rust import ExprGraph
assert sys.version_info[:2] == (3, 14), sys.version_info
print(sys.version_info[:2], ExprGraph.__module__)
"

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

build_sdist:
if: startsWith(github.event.release.tag_name, 'pybamm-v')
runs-on: ubuntu-latest
permissions:
Expand All @@ -19,26 +88,36 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: true
# Full history + tags so hatch-vcs can resolve the pybamm-v* version.
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: 3.14
python-version: 3.13

- name: Build sdist
run: pipx run build --sdist packages/pybamm --outdir deploy

- name: Guard the sdist size
# A force-include entry pointing one level too high would vendor the
# multi-gigabyte Cargo target/ tree. Fail rather than publish it.
run: |
size=$(stat -c%s deploy/*.tar.gz)
echo "sdist is $size bytes"
test "$size" -lt 52428800 || { echo "sdist over 50 MB - check sdist force-include"; exit 1; }
! tar -tzf deploy/*.tar.gz | grep -q "pybamm-rust/target/"

- name: Build wheel
# Build the pybamm workspace package (its pyproject now lives under packages/).
run: pipx run build packages/pybamm --outdir deploy
- name: Check sdist metadata
run: pipx run twine check --strict deploy/*.tar.gz

- name: Upload package
- name: Upload sdist
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: distributions
path: deploy/
name: pybamm_sdist
path: deploy/*.tar.gz
if-no-files-found: error

publish:
needs: build
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
environment: pypi
permissions:
Expand Down
55 changes: 54 additions & 1 deletion .github/workflows/test_on_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jobs:
- '.github/workflows/_build_solver_wheels.yml'
pybamm:
- 'packages/pybamm/**'
- 'packages/pybamm-rust/**'
- 'pyproject.toml'
- 'uv.lock'
- 'noxfile.py'
Expand Down Expand Up @@ -89,6 +90,50 @@ jobs:
echo "macos_runners=$macos"
} >> "$GITHUB_OUTPUT"

rust_msrv:
needs: changes
if: ${{ github.event_name == 'push' || needs.changes.outputs.pybamm == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
name: Rust MSRV (1.89)
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Install the MSRV toolchain
run: rustup toolchain install 1.89 --profile minimal --no-self-update
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
workspaces: packages/pybamm-rust
key: msrv-1.89
- name: Check against the declared MSRV
run: >
cargo +1.89 check --manifest-path packages/pybamm-rust/Cargo.toml
--locked --all-targets

rust_tests:
needs: changes
if: ${{ github.event_name == 'push' || needs.changes.outputs.pybamm == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
name: Rust tests
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
workspaces: packages/pybamm-rust
key: tests
# Includes the ABI drift tests, which read the pybammsolvers consumer
# header, so a cross-language contract break fails here.
- name: Run the Rust test suite
run: >
cargo test --manifest-path packages/pybamm-rust/Cargo.toml
--locked --workspace --all-features

style:
runs-on: ubuntu-latest
permissions:
Expand All @@ -102,6 +147,9 @@ jobs:
with:
python-version: 3.12

- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
workspaces: packages/pybamm-rust
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "latest"
Expand Down Expand Up @@ -202,7 +250,7 @@ jobs:
# Guards both the bootstrap and the clean-clone dev experience.
from_source_smoke:
needs: changes
if: ${{ github.event_name == 'push' || needs.changes.outputs.solver == 'true' }}
if: ${{ github.event_name == 'push' || needs.changes.outputs.solver == 'true' || needs.changes.outputs.pybamm == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -225,6 +273,9 @@ jobs:
with:
python-version: 3.13

- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
workspaces: packages/pybamm-rust
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "latest"
Expand Down Expand Up @@ -289,6 +340,8 @@ jobs:
needs:
- changes
- style
- rust_msrv
- rust_tests
- build_solver
- run_unit_tests
- run_coverage
Expand Down
13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,16 @@ repos:
additional_dependencies: [pyyaml]
files: ^\.github/(workflows/test_on_push\.yml|scripts/check_ci_gate\.py)$
pass_filenames: false
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --manifest-path packages/pybamm-rust/Cargo.toml --all
language: system
types: [rust]
pass_filenames: false
- id: cargo-clippy
name: cargo clippy
entry: cargo clippy --manifest-path packages/pybamm-rust/Cargo.toml --all-targets --fix --allow-dirty --allow-staged
language: system
types: [rust]
pass_filenames: false
args: ["--", "-D", "warnings"]
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ gets wrong:
`import matplotlib` breaks `import pybamm` for minimal installs.
- Public, user-facing objects are re-exported through `packages/pybamm/src/pybamm/__init__.py` (users write
`pybamm.X`) and get a `docs/source/api/*.rst` entry.
- **The Rust bindings ship hand-written stubs.** Any change to the Python-visible API in
`packages/pybamm-rust/pybamm-python/src` must update `packages/pybamm/src/pybamm/rust/_core.pyi`
in the same commit. `mypy.stubtest` (run by `tests/unit/test_rust_stubs.py`) machine-checks
names, arities and defaults against the built extension; the types are review-enforced, so keep
them as precise as the bindings' own coercions (e.g. the `p` dict-or-array union).
- Every feature or fix adds a `CHANGELOG.md` bullet under `# [Unreleased]` (Keep a Changelog
format), ending with the PR link, e.g. `([#1234](https://github.com/pybamm-team/PyBaMM/pull/1234))`.

Expand Down
Loading
Loading