Skip to content

fix: Quantity repr/format crashes and wrong format-spec semantics #411

fix: Quantity repr/format crashes and wrong format-spec semantics

fix: Quantity repr/format crashes and wrong format-spec semantics #411

Workflow file for this run

# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Continuous Integration
on:
push:
branches:
- main
pull_request:
permissions:
contents: read # to fetch code
actions: write # to cancel previous workflows
# This is what will cancel the workflow
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
type_check:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.13" ]
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip cache purge
python -m pip install --upgrade pip setuptools --no-cache-dir
python -m pip install -r requirements-dev.txt --no-cache-dir
python -m pip install 'mypy>=1.11,<3' --no-cache-dir
pip install . --no-cache-dir
- name: Run mypy
run: |
mypy saiunit/
test_no_jax:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.13" ]
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies (without JAX)
run: |
python -m pip cache purge
python -m pip install --upgrade pip setuptools --no-cache-dir
python -m pip install -r requirements.txt --no-cache-dir
python -m pip install pytest --no-cache-dir
pip install . --no-cache-dir
- name: Verify JAX is not installed
run: |
python -c "import importlib.util, sys; assert importlib.util.find_spec('jax') is None, 'jax should not be installed'; print('OK: JAX is not installed')"
- name: Verify top-level import works
run: |
python -c "import saiunit as u; print('saiunit', u.__version__); q = u.Quantity(3.0, u.meter); print('Quantity:', q)"
- name: Verify JAX-only submodules raise BackendError
run: |
python -c "import saiunit as u; from saiunit._exceptions import BackendError
for name in ('autograd', 'lax', 'sparse'):
try:
getattr(u, name)
except BackendError as e:
print(f'OK: u.{name} raised BackendError: {e}')
else:
raise SystemExit(f'FAIL: u.{name} should have raised BackendError')"
- name: Run no-jax smoke tests
run: |
pytest saiunit/_no_jax_test.py -v
# ---------------------------------------------------------------------------
# Per-backend isolation jobs.
#
# Each job below installs exactly ONE array backend on top of the base
# `requirements.txt` (numpy + array_api_compat) and runs the full test
# suite with that backend set as the saiunit default via the
# `SAIUNIT_DEFAULT_BACKEND` env var (read in conftest.py).
#
# Goal: prove that `pip install saiunit[<backend>]` works end-to-end and
# that backend-specific kwargs / hidden cross-backend dependencies cannot
# leak through saiunit's public API.
#
# The previous ``test_linux`` / ``test_macos`` / ``test_windows`` "install
# everything" matrix was removed: ``test_pure_jax`` is the same workload on
# Linux (saiunit's primary support target), and the per-backend isolation
# jobs catch the cross-backend bugs the multi-backend matrix could not.
#
# cupy is intentionally not included: GitHub free runners have no GPU.
# ---------------------------------------------------------------------------
test_pure_numpy:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.13" ]
env:
SAIUNIT_DEFAULT_BACKEND: numpy
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install (numpy backend only)
run: |
python -m pip cache purge
python -m pip install --upgrade pip setuptools --no-cache-dir
python -m pip install -r requirements.txt --no-cache-dir
python -m pip install pytest --no-cache-dir
python -m pip install matplotlib --no-cache-dir
pip install . --no-cache-dir
- name: Verify only numpy backend is installed
run: |
python -c "import importlib.util as u
for name in ('jax', 'torch', 'cupy', 'dask', 'ndonnx'):
assert u.find_spec(name) is None, f'{name} should not be installed in pure-numpy job'
print('OK: only numpy backend installed')"
- name: Test with pytest
run: |
pytest saiunit/
test_pure_jax:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.13" ]
env:
SAIUNIT_DEFAULT_BACKEND: jax
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install (jax backend only)
run: |
python -m pip cache purge
python -m pip install --upgrade pip setuptools --no-cache-dir
python -m pip install -r requirements.txt --no-cache-dir
python -m pip install pytest --no-cache-dir
python -m pip install jax --no-cache-dir
# Test-only deps used by the JAX-touching test files
# (saiunit/fft/, saiunit/lax/, saiunit/linalg/, saiunit/math/,
# saiunit/sparse/, custom_array_test.py). Neither pulls in
# another array backend.
python -m pip install absl-py brainstate --no-cache-dir
pip install . --no-cache-dir
# Replace the brainstate-pulled PyPI brainunit with the local one,
# so it tracks the in-tree saiunit (PyPI brainunit may import names
# this PR has removed).
python make_brainunit_setup.py
pip install ./brainunit --force-reinstall --no-deps --no-cache-dir
- name: Verify only jax backend is installed
run: |
python -c "import importlib.util as u
for name in ('torch', 'cupy', 'dask', 'ndonnx'):
assert u.find_spec(name) is None, f'{name} should not be installed in pure-jax job'
assert u.find_spec('jax') is not None, 'jax must be installed'
print('OK: only jax backend installed')"
- name: Test with pytest
run: |
pytest saiunit/
test_pure_torch:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.13" ]
env:
SAIUNIT_DEFAULT_BACKEND: torch
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install (torch backend only, CPU wheel)
run: |
python -m pip cache purge
python -m pip install --upgrade pip setuptools --no-cache-dir
python -m pip install -r requirements.txt --no-cache-dir
python -m pip install pytest --no-cache-dir
pip install torch --index-url https://download.pytorch.org/whl/cpu --no-cache-dir
pip install . --no-cache-dir
- name: Verify only torch backend is installed
run: |
python -c "import importlib.util as u
for name in ('jax', 'cupy', 'dask', 'ndonnx'):
assert u.find_spec(name) is None, f'{name} should not be installed in pure-torch job'
assert u.find_spec('torch') is not None, 'torch must be installed'
print('OK: only torch backend installed')"
- name: Test with pytest
run: |
pytest saiunit/
test_pure_dask:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.13" ]
env:
SAIUNIT_DEFAULT_BACKEND: dask
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install (dask backend only)
run: |
python -m pip cache purge
python -m pip install --upgrade pip setuptools --no-cache-dir
python -m pip install -r requirements.txt --no-cache-dir
python -m pip install pytest --no-cache-dir
pip install 'dask[array]' --no-cache-dir
pip install . --no-cache-dir
- name: Verify only dask backend is installed
run: |
python -c "import importlib.util as u
for name in ('jax', 'torch', 'cupy', 'ndonnx'):
assert u.find_spec(name) is None, f'{name} should not be installed in pure-dask job'
assert u.find_spec('dask.array') is not None, 'dask.array must be installed'
print('OK: only dask backend installed')"
- name: Test with pytest
run: |
pytest saiunit/
test_pure_ndonnx:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.13" ]
env:
SAIUNIT_DEFAULT_BACKEND: ndonnx
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install (ndonnx backend only)
run: |
python -m pip cache purge
python -m pip install --upgrade pip setuptools --no-cache-dir
python -m pip install -r requirements.txt --no-cache-dir
python -m pip install pytest --no-cache-dir
pip install ndonnx --no-cache-dir
pip install . --no-cache-dir
- name: Verify only ndonnx backend is installed
run: |
python -c "import importlib.util as u
for name in ('jax', 'torch', 'cupy', 'dask'):
assert u.find_spec(name) is None, f'{name} should not be installed in pure-ndonnx job'
assert u.find_spec('ndonnx') is not None, 'ndonnx must be installed'
print('OK: only ndonnx backend installed')"
- name: Test with pytest
run: |
pytest saiunit/