Skip to content

Commit a496c36

Browse files
Jammy2211claude
authored andcommitted
docs(chapter_1): restore truncated tutorials + add completeness CI check
tutorial_1_grids_and_galaxies and tutorial_2_ray_tracing were cut off mid-generation during the workspace bootstrap, each ending on a docstring that promised a plot with no code following and no Wrap Up (frozen at the truncated length since bootstrap commit #1; the original workspace source no longer exists). Restore the lost content: - tutorial_1: log10 image + __Galaxies__ + __Units__ + __Wrap Up__ + advanced topics, adapted from the complete HowToGalaxy sibling to the autolens API and lens framing (429 -> 672 lines). - tutorial_2: log-space convergence/potential + __Ray Tracing Grids__ (lens equation) + __Ray Tracing Images__ + __Galaxies__ + __Tracer__ + __Mappings__ + __Wrap Up__, sourced from guides/tracer.py (214 -> 391 lines). Both validated end-to-end and via the curated smoke suite (6/6). Prevent recurrence: add .github/scripts/check_tutorials_complete.py + a CI workflow that fails when any tutorial lacks a terminal __Wrap Up__/__Summary__ section — a truncated script never reaches its wrap-up, so absence of the marker reliably flags lost content. Normalize five complete-but-unmarked tutorials (tutorial_4_dealing_with_failure, tutorial_4_bayesian_regularization, tutorial_6_slam, tutorial_8_model_fit, tutorial_searches) with the terminal marker so they pass. Regenerate notebooks + navigator catalogue. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KExk2jkn2ya21b6NZLALpB
1 parent 93b520a commit a496c36

18 files changed

Lines changed: 1284 additions & 12 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env python3
2+
"""Fail if any HowTo tutorial script looks truncated.
3+
4+
Several tutorial scripts were once cut off mid-generation (a long file was
5+
re-emitted and the output was severed), losing all content below the cut and
6+
leaving a script that ends part-way through — typically on a docstring that
7+
promises a plot or code block which never appears. This check guards against
8+
that regression recurring.
9+
10+
A tutorial is considered *complete* when it contains a recognised terminal
11+
section marker (``__Wrap Up__`` or ``__Summary__``). A truncated script never
12+
reaches its wrap-up, so the absence of the marker is a reliable signal that the
13+
script lost content. Deliberate "not written yet" stub tutorials still carry a
14+
``__Wrap Up__`` section, so they pass.
15+
16+
A second, cheaper guard flags any script whose final docstring block ends on a
17+
colon (``:``) — the classic "a plot/code block follows" promise left dangling
18+
by a mid-docstring cutoff.
19+
20+
Run from the repo root::
21+
22+
python scripts/check_tutorials_complete.py
23+
24+
Exit status is non-zero if any tutorial fails, listing each offender.
25+
"""
26+
from __future__ import annotations
27+
28+
import re
29+
import sys
30+
from pathlib import Path
31+
32+
TERMINAL_MARKERS = ("__wrap up__", "__summary__")
33+
34+
35+
def final_docstring(text: str) -> str | None:
36+
"""Return the last triple-quoted block if it sits at the end of the file."""
37+
blocks = list(re.finditer(r'"""(.*?)"""', text, re.DOTALL))
38+
if not blocks:
39+
return None
40+
last = blocks[-1]
41+
if text[last.end():].strip() == "":
42+
return last.group(1)
43+
return None
44+
45+
46+
def check(path: Path) -> str | None:
47+
"""Return a failure reason for a truncated-looking tutorial, else None."""
48+
text = path.read_text(encoding="utf-8")
49+
if not any(marker in text.lower() for marker in TERMINAL_MARKERS):
50+
return "no __Wrap Up__/__Summary__ terminal section (looks truncated)"
51+
trailing = final_docstring(text)
52+
if trailing is not None and trailing.strip().endswith(":"):
53+
return "final docstring ends on ':' (dangling promise of a following block)"
54+
return None
55+
56+
57+
def main(root: str) -> int:
58+
scripts_dir = Path(root) / "scripts"
59+
files = sorted(scripts_dir.rglob("tutorial_*.py"))
60+
61+
failures = [(f, reason) for f in files if (reason := check(f)) is not None]
62+
63+
print(f"Checked {len(files)} tutorial scripts under {scripts_dir}.")
64+
if failures:
65+
print(f"\n{len(failures)} tutorial(s) look incomplete / truncated:\n")
66+
for f, reason in failures:
67+
print(f" [FAIL] {f.relative_to(root)}{reason}")
68+
print(
69+
"\nEach tutorial must end with a `__Wrap Up__` (or `__Summary__`) "
70+
"section. If a script is genuinely truncated, restore its lost "
71+
"content; if it is complete, add the terminal section."
72+
)
73+
return 1
74+
75+
print("All tutorial scripts have a terminal section — none look truncated.")
76+
return 0
77+
78+
79+
if __name__ == "__main__":
80+
raise SystemExit(main(sys.argv[1] if len(sys.argv) > 1 else "."))
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Tutorials Complete
2+
3+
# Guards against tutorial scripts being truncated / cut off mid-generation (a
4+
# long file re-emitted with the output severed, losing every section below the
5+
# cut). Each tutorial_*.py must end with a `__Wrap Up__` (or `__Summary__`)
6+
# terminal section; the check is pure-stdlib and needs no library install.
7+
# See scripts/check_tutorials_complete.py.
8+
9+
on: [push, pull_request]
10+
11+
jobs:
12+
tutorials-complete:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-python@v5
17+
with:
18+
python-version: "3.13"
19+
- name: Check tutorials are not truncated
20+
run: python .github/scripts/check_tutorials_complete.py .

llms-full.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ AUTO-GENERATED by PyAutoBuild — do not edit by hand; regenerate with generate.
1212
- [Tutorial 0: Visualization](scripts/chapter_1_introduction/tutorial_0_visualization.py): In this tutorial, we quickly cover visualization in **PyAutoLens** and make sure images display clearly in your Jupyter notebook and on your computer screen.
1313
- Contents: Directories, Dataset, Subplots, Plot Customization, Overlays, Wrap Up
1414
- [HowToLens: Introduction](scripts/chapter_1_introduction/tutorial_1_grids_and_galaxies.py): A strong gravitational lens is a system where two (or more) galaxies align perfectly down our line of sight from Earth such that the foreground galaxy's mass curves space-time in on itself, such that the light of a background source galaxy is deflected and magnified. This means we can see the background source galaxy multiple times, as multiple arcs or rings, because multiple paths through the foreground galaxy's mass are taken by the source's light.
15-
- Contents: Grids, Geometry, Light Profiles, One Dimension Projection
15+
- Contents: Grids, Geometry, Light Profiles, One Dimension Projection, Galaxies, Units
1616
- [Tutorial 2: Ray Tracing](scripts/chapter_1_introduction/tutorial_2_ray_tracing.py): Strong gravitational lensing occurs when the mass of a foreground galaxy (or galaxies) curves space-time around it, causing light rays from a background source to appear deflected.
17-
- Contents: Grid, Mass Profiles
17+
- Contents: Grid, Mass Profiles, Ray Tracing Grids, Ray Tracing Images, Galaxies, Tracer, Mappings
1818
- [Tutorial 5: More Ray Tracing](scripts/chapter_1_introduction/tutorial_3_more_ray_tracing.py): We'll now reinforce the ideas that we learnt about ray-tracing in the previous tutorial and introduce the following new concepts:
1919
- Contents: Initial Setup, Concise Code, Critical Curves, Caustics, Units, More Complexity, Multi Galaxy Ray Tracing, Wrap Up
2020
- [Tutorial 4: Point Sources](scripts/chapter_1_introduction/tutorial_4_point_sources.py): This tutorial is not wrriten yet, but will explain how point source lensing works.

0 commit comments

Comments
 (0)