docs: hostile-read fixes to the README #7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| # Lint and the CPU test suite on every push and PR to main. | |
| # GPU-marked tests are excluded here by design: every test in `tests/` is written | |
| # to run on CPU in under 5 seconds, and `-m "not gpu"` is the contract that keeps | |
| # that promise enforceable on a runner with no CUDA device. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint-and-test: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 40 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.10", "3.12"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: pip | |
| # CPU-only torch. The default wheels pull ~2.5 GB of CUDA libraries that a | |
| # runner can neither use nor fit comfortably; this index serves the same | |
| # torch/torchvision versions built without them. | |
| - name: Install CPU-only torch | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu | |
| - name: Install project | |
| run: pip install -e ".[dev]" | |
| - name: Lint | |
| run: ruff check src/ tests/ scripts/ | |
| # Same three trees as the lint step above. They were src/ and tests/ only, | |
| # which let a badly formatted file in scripts/ pass a green build. | |
| - name: Format check | |
| run: ruff format --check src/ tests/ scripts/ | |
| # 26 tests call build_datasets, which is download=True — without this every | |
| # job re-fetches ~170 MB from toronto.edu, twice per push across the matrix, | |
| # and a red badge caused by someone else's flaky host is still a red badge. | |
| # The key is fixed: CIFAR-10 is a frozen dataset, so the cache never needs | |
| # to be invalidated. | |
| - name: Cache CIFAR-10 | |
| uses: actions/cache@v4 | |
| with: | |
| path: data/ | |
| key: cifar10-python-v1 | |
| # Fetched in its own bounded step rather than lazily inside pytest. The | |
| # first run of this workflow proved why: `pytest` inherited the download, | |
| # produced no output for nineteen minutes, and was killed by the job | |
| # timeout with no indication of what it had been doing. Here a stall costs | |
| # a bounded 20 minutes, is attributed to the right step, and | |
| # `continue-on-error` lets the suite proceed -- the ten dataset tests then | |
| # skip visibly via `requires_cifar10` instead of hanging the job. | |
| # | |
| # The bound was raised by measurement, not guesswork: 5 minutes reached | |
| # 26.4%, and 20 minutes reached 99.2% before timing out with 0.8% to go. | |
| # 25 gives that margin. The host is simply slow from cloud runners, and | |
| # this is paid once -- a completed fetch populates the cache above under a | |
| # fixed key, and every later run restores it in seconds. The bound stays | |
| # strictly below the job's 40 so a stalled fetch can never be what | |
| # consumes the job. | |
| - name: Fetch CIFAR-10 | |
| continue-on-error: true | |
| timeout-minutes: 25 | |
| run: | | |
| python - <<'PY' | |
| from torchvision.datasets import CIFAR10 | |
| CIFAR10(root="data", train=True, download=True) | |
| CIFAR10(root="data", train=False, download=True) | |
| PY | |
| # -rs reports skip reasons, so a green build that quietly skipped the | |
| # dataset tests is visible as such rather than looking like a full pass. | |
| - name: Test (CPU only) | |
| run: pytest -m "not gpu" -q -rs |