Skip to content

Publish executed notebooks to the PR preview for review - #205

Merged
bendichter merged 1 commit into
masterfrom
executed-notebook-previews
Aug 22, 2026
Merged

Publish executed notebooks to the PR preview for review#205
bendichter merged 1 commit into
masterfrom
executed-notebook-previews

Conversation

@bendichter

Copy link
Copy Markdown
Member

Reviewing a notebook PR today means reading source with no outputs, or running it yourself. This makes CI do the running and hand reviewers the result.

How it works. run_notebook.py gains --executed-output, which executes the notebook through a real Jupyter kernel via nbconvert --execute (the same path a user's Run All takes) instead of the ipython script path, and keeps the executed notebook with its outputs. It runs with --allow-errors so a failing notebook still produces a complete executed copy, then scans the outputs to decide pass or fail. The PR workflow renders each executed notebook to HTML, uploads it as an artifact, and a final job deploys all of them into the PR's existing preview directory on gh-pages (pr-preview/<PR>/notebooks/) and posts a sticky comment linking each one with a pass/fail mark. The existing preview cleanup removes the directory when the PR closes, so nothing is ever committed to the branch or to master.

Fork PRs. Workflows triggered from forks get a read-only token and cannot deploy, so they keep the executed notebooks as downloadable artifacts; same-repo PRs get the clickable links. Many notebook PRs currently come from the catalystneuro fork; branching in this repo gets them the full experience.

Deploy safety. All gh-pages deploys (index, preview, executed notebooks) now share one concurrency group, so two workflows can never push to the branch at the same time (the class of race behind yesterday's preview 404s).

Verified locally inside a published image: a passing notebook yields an executed copy with 31 outputs and 6 figures and a done verdict; a copy with an injected failing cell is reported as failed at that cell with the executed notebook kept so the error is visible. Workflows validated with actionlint. This PR changes no notebooks, so the comment will first appear on the next notebook PR; I have the 001712 fixes ready to open right after, which will serve as the live demonstration.

🤖 Generated with Claude Code

The PR workflow now executes each changed notebook through a real
Jupyter kernel (run_notebook.py gains --executed-output, which runs
nbconvert --execute instead of the ipython script path and keeps the
executed notebook with its outputs), renders it to HTML, uploads it as
an artifact, and, for same-repo PRs, deploys the HTML into the PR's
preview directory on gh-pages and posts a sticky comment linking each
executed notebook with its pass/fail status. Reviewers can read plots
and results as a reader would, without running anything. The copies
live only in the preview and are removed by the existing cleanup when
the PR closes; nothing is committed to the branch. Fork PRs keep the
artifact, since their token cannot deploy.

All gh-pages deploys (index, preview, executed notebooks) now share one
concurrency group so pushes to the branch never race.

Verified locally inside a published image: a passing notebook yields an
executed copy with 31 outputs and 6 figures and a done verdict; a copy
with an injected failing cell is reported as failed at that cell, with
the executed notebook kept so the error is visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Aug 22, 2026
@github-actions

github-actions Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Preview for this PR has been removed (PR closed).

@bendichter
bendichter merged commit 492a63f into master Aug 22, 2026
6 checks passed
github-actions Bot added a commit that referenced this pull request Aug 22, 2026
bendichter added a commit that referenced this pull request Aug 23, 2026
…-lock

The first CI round on the 3.13 re-lock failed 22 notebooks. Fourteen of
those were artifacts of the kernel execution path added in #205 rather
than of the re-lock: nbconvert starts the kernel in the directory of the
notebook file it is given, which was our temporary copy under /tmp, so
helper modules and relative data paths next to the original notebook
were not found; and tqdm.auto raises "IProgress not found" inside a
kernel when ipywidgets is missing, which Colab preinstalls and our
runner did not. The temporary copy now lives beside the original, and
ipywidgets is installed with the harness in kernel mode.

The remaining eight were real drift that the old locks had masked:
pynapple 0.11 removed compute_perievent_continuous and the tref kwarg,
numcodecs 0.16 removed blosc.cbuffer_sizes (used by lindi), and pynwb
3.1 rejects object names containing "/" that the 001038 and 001084
files carry. Each gets an upper bound in its requirements.in. Holding
pynwb below 3.1 in turn needs a dandi release that wants click<8.2,
which conflicts with Colab's click pin, so lock_notebook.py now honours
"# override: <spec>" lines in requirements.in that replace the Colab
constraint for a single package. The MICrONS notebook drops its
nwbwidgets cell, since that package forces a pynwb the server-side
dandi version check no longer accepts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011NuStoQykizhQCx2KBrMCN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant