Developing tu-cookbook-python¶
This page is for people contributing to this repository — the Copier template and the tu-cookbook CLI — not for people writing notebooks inside a cookbook that was generated from it. If that's what you're after, see the CONTRIBUTING.md that ships inside a generated cookbook (template/CONTRIBUTING.md in this repo).
Project Layout¶
tu-cookbook-python/
├── copier.yml # prompts asked by `copier copy`
├── extensions.py # Jinja filters/globals used by copier.yml and the template
├── justfile # dev commands for THIS repo
├── pyproject.toml # this repo's own package: the `tu-cookbook` CLI
├── src/tu_cookbook_python/ # the CLI itself
│ ├── cmd/new.py # `tu-cookbook new` — scaffolds a notebook in a cookbook
│ ├── cmd/fix_urls.py # `tu-cookbook fix-urls`
│ ├── _git.py # git remote parsing helpers
│ └── _writer.py
├── template/ # the Copier template — copied into every generated cookbook
│ ├── Justfile # a DIFFERENT justfile, shipped to end users
│ ├── CONTRIBUTING.md # a DIFFERENT contributing guide, for cookbook authors
│ ├── pyproject.toml.jinja
│ └── ...
├── tests/
│ ├── template/ # renders the template and asserts on the output
│ └── tu_cookbook_python/ # unit tests for the CLI
├── docs/ # this documentation site (zensical)
└── scripts/ # maintainer tooling (dependency sync)
The core idea: this repo is a template factory, not a cookbook. Nothing under template/ runs directly here — it's rendered by Copier into a new git repository. Everything else (src/, tests/, docs/, extensions.py, copier.yml) exists to build, test, and document that template and its companion CLI.
How the Pieces Fit Together¶
copier.ymldefines the questionscopier copyasks (project_name,license,editor, ...) and registers the Jinja extensions used while rendering.extensions.pyprovides the custom Jinja filters/globals referenced fromcopier.ymland the template files themselves — e.g.cookbookify,slugify,git_user_name. The root-leveltest_extensions.pyunit-tests these directly, independent of any template rendering.template/is the actual template. File and directory names can themselves contain Jinja ({% if use_license %}LICENSE{% endif %}.jinja), and any.jinja-suffixed file is rendered before being written into the generated project.src/tu_cookbook_python/is a separate, installable CLI (tu-cookbook) that generated cookbooks depend on for day-to-day tasks, such as scaffolding a new notebook (tu-cookbook new, wired up as thenewrecipe intemplate/Justfile) or fixing Binder URLs (tu-cookbook fix-urls).
justfile — This Repo's Dev Commands¶
Important
This repo's root `justfile` is a **different file** from `template/Justfile`. The root one runs commands against *this* repository; `template/Justfile` is itself a template file that gets rendered into every generated cookbook. Don't confuse recipes between the two when reading either file.
Run just to list all recipes. Some worth knowing:
just venv—uv syncthis repo's own dependencies (copier, pytest, ruff, ty, zensical, ...)just check— lint, format, and type-check (ruff check,ruff format,ty check)just test— run the test suitejust render— render the template into./renderedwith a fixed set of example answers, for manually inspecting generated outputjust docs— serve this documentation site locallyjust hooks-install/just hooks— install / run the pre-commit hooks
How the Tests Work¶
tests/ splits along the same line as the codebase itself:
tests/template/tests the template, not Python code.tests/conftest.pydefines acopied_projectfixture that runscopier.run_copy()against this repo (vcs_ref="HEAD") with a fixed set of answers, producing a real rendered project in a temp directory once per test module. Tests then assert against the rendered files:test_copier.pychecks the full generated file tree against an explicit allow-list, and spot-checks that Jinja substitutions (project name, author, license, ...) landed correctly in files likeCITATION.cff,myst.yml, andpyproject.toml.test_copy_licenses.pychecks that each license choice renders the correctLICENSEtext.test_jinja_tags.pyscans every file undertemplate/for{{ variable }}tags and asserts each one is actually defined incopier.yml(plus a small allow-list forjust/ruffsyntax that looks similar) — this catches typo'd template variables that would otherwise only surface when someone actually runscopier copy.tests/tu_cookbook_python/are ordinary unit tests for the CLI package insrc/, exercising git-remote parsing, Binder URL construction, and thenew/fix-urlscommands directly — no template rendering involved.
Run everything with just test, or target one half directly with uv run pytest tests/template / uv run pytest tests/tu_cookbook_python.
Maintainer-Only¶
The following are run by maintainers, not typical contributors:
just release <target>runs the tests, bumps the version (uv version), regeneratesCHANGELOG.mdfrom Conventional Commits, commits, and tags. Pushing is left to the maintainer (git push && git push --tags).scripts/update_template_dependencies.py(wired up as the_updaterecipe) scanstemplate/for pinned dependency versions — per rules declared inscripts/dependency_rules.json— and bumps them to the latest release on PyPI, committing the result. This keeps every newly-generated cookbook'spyproject.toml/environment.ymlon current dependency versions without a maintainer doing it by hand.