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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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