Created: 2026-09-29
Board: Task 11 in PROJECT_BOARD.md
Status: Propagated to soln/ 2026-09-29; not yet built or published
A reader on https://allendowney.github.io/ThinkPython should be able to open the chapter they are reading as a runnable notebook on Colab, from every chapter.
Colab link in soln/ |
Appears on the site | |
|---|---|---|
chap00 |
yes — prose in Getting started | yes |
chap01 |
yes — "Welcome" cell | no |
chap02–chap19 |
none | no |
Two separate problems, and the second is the larger one.
chap01's link is hidden. Cell 1 is a # Welcome markdown cell containing both a
link to the Jupyter intro and a "click here to run this notebook on Colab" link
pointing at chapters/chap01.ipynb — the right target. The cell is tagged
remove-cell, which tells Jupyter Book to drop it from the rendered HTML, so the link
never reaches the website. The same applies to cell 37, which has a second Colab link
in the %%expect note.
The tag looks deliberate rather than accidental: the cell is written in notebook voice ("This is the Jupyter notebook for Chapter 1… if you are not already running this notebook on Colab"), which reads wrong on a web page. Simply removing the tag would expose prose that does not belong there.
Chapters 2–19 have no link at all, in soln/, chapters/, or jb/. There is
nothing to un-hide for 18 of the 20 chapters.
Add an explicit, untagged markdown cell near the top of each chapter.
Considered and rejected: Jupyter Book's launch_buttons. Setting
launch_buttons.colab_url in jb/_config.yml adds a rocket-ship button to the header
of every notebook page automatically, with no per-chapter edits. Reading
sphinx_book_theme/header_buttons/launch.py confirms it would work here: the URL is
built as {colab_url}/github/{org}/{repo}/blob/{branch}/{path_rel_repo}, and
path_rel_repo comes from the path_to_docs theme option, which Jupyter Book maps
from repository.path_to_book. Setting path_to_book: chapters would therefore
produce exactly …/blob/v3/chapters/chapNN.ipynb. Markdown pages (index.md,
blank.md) would be skipped, because the button is gated on _is_notebook, which
tests for kernelspec metadata.
It was rejected in favour of an explicit cell, which gives full control over wording and placement and puts the link in the flow of the page rather than in theme chrome. Recorded here because it remains the cheaper option if the per-chapter cells become a maintenance burden.
Wording, matching the pattern already used in Think Bayes 2e
(examples/hospital_birth_rate.ipynb):
[Run this notebook on Colab](https://colab.research.google.com/github/AllenDowney/ThinkPython/blob/v3/chapters/chapNN.ipynb)- Untagged, so it appears in the HTML and in the downloadable notebooks.
- Placed immediately after the chapter's H1, not before it — so a page reads header, title, link, content. This also matches Think Bayes 2e.
- Targets
chapters/chapNN.ipynb— the student notebook, not the solution. - Deliberately omits any "if you are not already running this on Colab" framing, which is what made the original chap01 wording unusable on the web.
- The Jupyter-intro link stays out of this cell; it is useful, but belongs in chap00 and chap01 rather than all twenty.
Known trade-off: in a downloaded notebook the link now sits after the setup cell that
downloads thinkpython.py, so a reader who wants Colab may already have run it
locally. Accepted, because the website is the problem being solved and a notebook
reader already has the file.
chap02–chap19: add the new cell.chap01: reconcile with the existingWelcomecell. Decide whether the Jupyter intro link survives, and whether theremove-celltag comes off or the cell is replaced.chap00: already discusses Colab in Getting started. Check the new cell does not contradict or duplicate it.- Leave cell 37 of
chap01alone; it is a note about%%expect, not a launch link.
Every chapter opens with the same untagged cell, which is also stored as
soln/header.ipynb:
You can order print and ebook versions of Think Python 3e from Bookshop.org and Amazon.
Since the Colab cell lands directly beneath it and both are edited in the same pass, revise it at the same time. For reference, Think Stats uses a more developed version:
The third edition of Think Stats is available now from Bookshop.org and Amazon (those are affiliate links). If you are enjoying the free, online version, consider buying me a coffee.
Open questions: whether to disclose the affiliate links, whether to add the coffee link, and whether the wording should differ between the website and the notebooks.
Editing soln/header.ipynb alone changes nothing. It is a template, and its text
has already been copied into every chapter as cell 0 — verified byte-identical in
20/20 chapters on 2026-09-29. The new wording has to be propagated after it is written.
soln/jntools.py provides add-header and add-footer, but they prepend
(notebook.cells = header.cells + notebook.cells), so running add-header would leave
each chapter with two order headers. It is the wrong tool for a replacement.
Because cell 0 is identical everywhere, propagation is a safe scripted substitution
rather than twenty hand edits: replace cell 0 where it matches the old text exactly,
and fail loudly on any chapter where it does not. The same script can insert the Colab
cell after the H1, since only chapNN varies. header.ipynb is untracked, and should
be committed alongside the change so the template and the chapters cannot drift.
Per chapter, using the established round-trip:
cd ThinkPythonSolutions/soln
jupytext --to md chapNN.ipynb # re-export first, so the md is fresh
# ... edit chapNN.md ...
jupytext --update --to ipynb chapNN.md # --update preserves stored outputsKeep the .md afterward; it is gitignored and serves as the recovery copy. Close any
Jupyter tab on a chapter before editing it.
Adding a markdown cell changes no code, so no chapter needs re-executing for this task. If the header revision is the only other change, the stored outputs stay valid.
Applied to all 20 chapters in soln/ by a scripted cell-level edit, which left cell
counts unchanged and all 789 output-bearing cells untouched. .md recovery copies were
regenerated afterwards.
- Header replaced in all 20, only where cell 0 matched the previous text exactly. The new text adds the affiliate disclosure and the coffee link.
- Colab link added to 18 chapters, placed inside the title cell directly beneath
the
# Heading. The title cells carry 47-182 words of chapter introduction, so a separate cell after them would have buried the link below the opening prose. chap00andchap19excluded. Both have exactly one code cell and it is empty, so "Run this notebook on Colab" would point at nothing to run.chap01's Welcome cell trimmed: the redundant "click here to run this notebook on Colab" sentence is gone, the Jupyter-intro link stays. The cell keeps itsremove-celltag, so it remains notebook-only orientation.
Two pre-existing issues surfaced:
-
The Amazon link carried the wrong affiliate tag — fixed. The URL had duplicate
tagand_encodingparameters,tag=oreilly20-20followed bytag=greenteapre01-20. Duplicated query parameters resolve inconsistently and the first occurrence commonly wins, so some or all attribution was going to O'Reilly's associate account rather than Green Tea Press. The URL had been copied unchanged into all 20 chapters,README.mdandjb/index.md, so it was on every page of the published site. Now a singletag=greenteapre01-20.linkCode,linkId,campandcreativewere left as they were: they come from the original generated link and are analytics identifiers, not attribution.No other Green Tea Press book is affected — the rest use a single correct tag.
-
bookshop.orgreturns 403 to a scripted request. Most likely bot filtering rather than a dead link, but it was not confirmed in a browser.
See "Reviewing the build process" below before running anything.
There are four build targets, each with its own build.sh:
| Target | What it does | Ends with |
|---|---|---|
chapters/ |
student notebooks + ThinkPythonNotebooks.zip |
git push |
blank/ |
code-free notebooks | git push |
jb/ |
Jupyter Book HTML | ghp-import -n -p -f → publishes the site |
| top level | copies support files, renders the SVG figures | git push |
ThinkPythonSolutions/update.py claims to automate this. It should not be trusted as
written — it has two gaps that match problems actually observed in the repo:
-
It never builds
blank/. It runschapters/,jb/, and the top level only. This is almost certainly whyblank/had drifted: rebuilding it on 2026-09-19 changed 14 files, far more than the three edited chapters. -
It never pushes
soln/. Step 1 commits the solution notebooks and stops. The laterbuild.shruns push ThinkPython, so the solutions commit can sit local indefinitely — and two unpushed "Update solution notebooks" commits were sitting there on 2026-09-19.
Further problems, in rough order of severity:
-
Failures do not stop it, and are reported as success.
run_commandprints "Warning: Command exited with code N" and continues;mainends with "✓ Update process completed!" regardless. A failedjb buildlooks like a clean run. -
It publishes the website with no confirmation. Step 3 runs
jb/build.sh, which ends inghp-import -n -p -f. Runningpython update.pypushes to GitHub Pages as a side effect, which is not obvious from the name or the docstring. -
Nothing re-executes the notebooks and nothing runs the tests. Stored outputs are published exactly as they sit on disk. This is the chapter 18 failure mode: source corrected, output stale, published anyway.
-
capture_output=Truehides progress. A multi-minutejb buildprints nothing until it finishes. -
Step 1 commits only
soln/chap*.ipynb. Changes tothinkpython.py,diagram.pyorstructshape.pyinsoln/are silently left out.
Run the steps by hand rather than via update.py, or fix update.py first.
1. edit soln/chapNN.md -> jupytext --update --to ipynb
2. cd ThinkPythonSolutions && make tests # 20 chapters, ~2.5 min
3. commit and PUSH ThinkPythonSolutions
4. cd chapters && bash build.sh # commits + pushes ThinkPython
5. cd blank && bash build.sh # the step update.py forgets
6. cd jb && bash build.sh # PUBLISHES the site
7. spot-check a built page for the new Colab link before accepting the publish
Step 2 is cheap insurance now that all 20 chapters are under test. Step 7 matters because the whole point of this task is a link that only appears in the rendered HTML.