jupytext-notebook-helper
Author your teaching notebooks once, in plain Python, and generate every version you hand out — while a build that actually runs the code keeps you honest.
Why
A single practical (TP) usually has to exist in several shapes at once:
- a teacher notebook with the full solutions,
- a student notebook where those solutions are blanked out,
- a Colab variant that installs its own dependencies,
- a local variant shipped with a pinned
uvenvironment, - optionally a solution hand-out (solutions kept, instructor scaffolding gone).
Maintaining those by hand means copy-pasting between notebooks, re-blanking
answers, chasing pip install lines, and discovering in front of the class
that a cell no longer runs. Notebooks are also miserable to diff and review in
git.
This project takes a different approach: you write one source file per TP in
the jupytext percent format — an ordinary, diffable, lintable .py file —
annotate it with a few lightweight markers, and a build step produces all the
variants above. The same build can execute each notebook (at three levels of
fidelity) so a broken example fails on your machine, not the student's.
The idea in one picture
┌─ student/ local/tp1.ipynb (solutions blanked)
│ colab/tp1.ipynb (+ auto %pip install cell)
tp1.py ──filter──▶ ├─ teacher/ local/tp1.ipynb (solutions kept)
(py:percent) │ colab/tp1.ipynb
└─ solution/ local/tp1.ipynb (optional corrigé)
colab/tp1.ipynb
│
└─ + uv bundle (pyproject + uv.lock + notebooks) for a reproducible
local install
Every output directory has the same two sub-directories, local/ and colab/,
with the same file names, so a link only changes by one path segment.
You author in tp1.py; students never see the machinery.
What you write
An ordinary percent notebook, with a small marker vocabulary interpreted by the
filter (python -m jupytext_notebook_helper.filter):
# %% [markdown]
# ## Exercise 1 — cosine similarity
# %%
import numpy as np
def cosine(a, b):
# [[student]] Return the cosine similarity of two vectors
return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
# [[/student]]
[[student]] … [[/student]] is blanked in the student version (the instruction
becomes a comment followed by assert False), [[remove]] … [[/remove]] is
stripped from everything handed out, and cell tags gate content per variant.
The full vocabulary is in Writing a source.
Percent files open as notebooks in VS Code with the
Text as Notebook
extension (with the Jupyter extension for the kernel): cells run against a real
kernel, and the file on disk stays the plain .py source.
What you get
Beyond the variant generation, the build integrates a few things that otherwise bite you late:
- Imports are gathered automatically from wherever you wrote them — put each
importnext to the code that needs it. - Internal library code is inlined so a self-contained student notebook carries exactly the helper functions it uses — nothing more.
- Colab gets a pinned
%pip installcell generated fromuv.lock, so the first cell just works. - Each practical says whether it is handed out, and whether its corrigé
goes with it, in its own header (
publish:/solution:) — so holding one back is one line in the file it concerns, and it keeps being built and checked meanwhile. - Everything is testable at three fidelity levels (
make check= resolved inlined subset,make check-raw= plain script, and the real notebook build), catching missing dependencies and broken cells before students do.
Quick start
Include the shared make rules from the course's Makefile:
ROOT := ..
include $(shell uv run python -m jupytext_notebook_helper.tpmk)
Then, from that directory:
make help # every target, by section
make student # student notebooks (local + Colab) and the uv bundle
make teacher # teacher notebooks, with the solutions
make check # run every source, with the code students get
Documentation
| Page | Covers |
|---|---|
| The pipeline, end to end | source → build → check → deploy → index page → manifest, with the target for each step |
| Writing a source | markers, gathered imports, inlined library code, the Colab install cell |
| Runtime helpers | where output goes (NOTEBOOK_OUTPUT), and what belongs to cs-lab instead: hardware() and the profile ladder |
| Checking and running | check, check-raw, lab, run-teacher, check-resources |
| Setting up a course | the Makefile, [tool.jupytext-notebook-helper], bundles, solutions, rsync, the index page |
| Breaking changes | what changed between major versions, and how to migrate |
The header of jupytext_notebook_helper/tp.mk lists every configurable
variable.
Metadata
Release files for jupytext-notebook-helper 3.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jupytext_notebook_helper-3.1.0.tar.gz | 108.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jupytext_notebook_helper-3.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 181.2 kB
Release files / jupytext_notebook_helper-3.1.0.tar.gz
| Download URL | jupytext_notebook_helper-3.1.0.tar.gz |
|---|---|
| Size | 108.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88645d9655e0f3260851d77fbbb6d076eeb4e2c14ddecf97cbbd61d4b58ac4b5
|
|
BLAKE2b-256 checksum How to use checksums |
26b2816256d474d89ac6cabeb1169b596dffae480387f2da931e45c0ab29ae9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logRelease files / jupytext_notebook_helper-3.1.0-py3-none-any.whl
| Download URL | jupytext_notebook_helper-3.1.0-py3-none-any.whl |
|---|---|
| Size | 72.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
99daf64eb021e8befd055a909ff1afc318bff49749fffa9282252ac33c63ad3b
|
|
BLAKE2b-256 checksum How to use checksums |
33adf1ab00b551ad6aa0500e5b1c5fe5b8154d7375e129c8290e4000cd4fe7f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency log