Skip to content

CI can't catch a missing Colab clone cell — add a static check (tests/test_colab_clone_cell.py) #442

Description

@kwlee2025cpp

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

"""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

Same theme: CI tests the repo, non-interactive path, not the Colab standalone path.

🤖 Filed via Claude Code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions