CI can't catch a missing Colab clone cell — add a static check (tests/test_colab_clone_cell.py)
- Dominant language
- Jupyter Notebook
- Stars
- 12
- Forks
- 76
- PR merge metrics
- No merged PRs in 30d
Description
## Problem
A notebook that imports an `nmisp_py` helper (`import matshow`, `jacobi`, `matrix`, `gauss_jordan`, …) **must** include the Google Colab clone cell, or it fails at `import` in Colab. **CI does not catch this**:
- the test jobs run `nbconvert --execute` in the repo checkout, where the helper `.py` files sit next to the notebooks → the import always resolves locally;
- the clone cell's `if 'google.colab' in str(get_ipython())` guard is `False` on a GitHub runner → the clone path is never exercised;
- `test_ipynb_colab` only swaps in Colab *dependency versions*, not Colab's *standalone* import environment.
## Concrete example
`60_linear_algebra_2/220_Google_PageRank.ipynb` imported `matshow` but had no clone cell — green in CI, broken in Colab — until it was added manually.
## Proposed fix: a fast static test (no execution) — `tests/test_colab_clone_cell.py`
```python
"""A notebook importing an nmisp_py helper must include the Colab clone cell."""
import json, pathlib, re, pytest
REPO = pathlib.Path(__file__).resolve().parents[1]
EXCLUDE = {'tests', 'utils', 'build_util', '.ipynb_checkpoints'}
HELPERS = {p.stem for p in REPO.rglob('*.py')
if not (set(p.relative_to(REPO).parts) & EXCLUDE) and p.stem != '__init__'}
NOTEBOOKS = [p for p in REPO.rglob('*.ipynb')
if not (set(p.relative_to(REPO).parts) & EXCLUDE)]
@pytest.mark.parametrize('nb', NOTEBOOKS, ids=lambda p: str(p.relative_to(REPO)))
def test_helper_import_has_colab_clone_cell(nb):
code = '\n'.join(''.join(c['source']) for c in json.loads(nb.read_text())['cells']
if c['cell_type'] == 'code')
used = sorted(({*re.findall(r'^\s*import\s+(\w+)', code, re.M),
*re.findall(r'^\s*from\s+(\w+)\s+import', code, re.M)} & HELPERS))
if used:
assert 'google.colab' in code, \
f"{nb.name} imports nmisp_py helper(s) {used} but has no Colab clone cell"
```
- Runs inside the existing `pytest ./tests` invocation, sub-second, one clear failure per offending notebook.
- **Passes today** (repo is clean after the recent fixes) and would have caught the 220 regression.
## Related
- #440 — `030` dead-kernel gates `test_ipynb_colab` *and* the `nmisp_py` auto-sync.
- #441 — CI can't exercise interactive `ipywidgets` callbacks.
Same theme: CI tests the *repo, non-interactive* path, not the *Colab standalone* path.
🤖 Filed via Claude Code.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.