Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/guid-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -3075,7 +3075,7 @@
"path": "scripts/assemble_todo.py",
"guid": "af7ef324-6c69-411e-b1a9-98c9ba2b31e3",
"title": "assemble todo",
"version": "1.1.0",
"version": "1.2.0",
"header_path": "scripts/assemble_todo.py",
"path_mismatch": false
},
Expand Down
15 changes: 15 additions & 0 deletions changelog.d/20260719-assembler-width-stable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### Fixed

#### `assemble_todo.py` is now formatted identically at any ruff line-length

`ruff format` is not idempotent across line-lengths: a file formatted at 80
columns gets its short lines rejoined at 88. The assembler is copied verbatim
into repos that have no `ruff.toml` of their own, where ruff falls back to its
88-column default — so `ruff format --check` failed there even though the file
was correctly formatted for this repo.

Every multi-line construct now carries a magic trailing comma (which pins it
exploded at any width), and the two constructs that could not take one were
reshaped to fit under 79 columns. Verified byte-identical output at widths 79,
80, 88, 100, 120 and 200, and the file passes `ruff check`/`ruff format --check`
under both this repo's config and a bare `--isolated` default.
22 changes: 13 additions & 9 deletions scripts/assemble_todo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# file: scripts/assemble_todo.py
# version: 1.1.0
# version: 1.2.0
# guid: af7ef324-6c69-411e-b1a9-98c9ba2b31e3
# last-edited: 2026-07-19

Expand Down Expand Up @@ -50,10 +50,12 @@
HTML_COMMENT = re.compile(r"<!--.*?-->", re.DOTALL)

VERSION_HEADER = re.compile(
r"^(<!--\s*version:\s*)(\d+)\.(\d+)\.(\d+)(\s*-->)$", re.M
r"^(<!--\s*version:\s*)(\d+)\.(\d+)\.(\d+)(\s*-->)$",
re.M,
)
LAST_EDITED_HEADER = re.compile(
r"^(<!--\s*last-edited:\s*)(\S+)(\s*-->)$", re.M
r"^(<!--\s*last-edited:\s*)(\S+)(\s*-->)$",
re.M,
)


Expand Down Expand Up @@ -81,9 +83,8 @@ def find_fragments(fragment_dir: Path) -> list[Path]:
"""
if not fragment_dir.is_dir():
return []
return sorted(
path for path in fragment_dir.glob("*.md") if path.name != "README.md"
)
candidates = fragment_dir.glob("*.md")
return sorted(p for p in candidates if p.name != "README.md")


def fragment_body(path: Path) -> str:
Expand Down Expand Up @@ -121,7 +122,9 @@ def _bump(match: re.Match[str]) -> str:
print("warning: no '<!-- version: X.Y.Z -->' header to bump.")

text, count = LAST_EDITED_HEADER.subn(
lambda m: f"{m.group(1)}{today}{m.group(3)}", text, count=1
lambda m: f"{m.group(1)}{today}{m.group(3)}",
text,
count=1,
)
if not count:
print("warning: no '<!-- last-edited: ... -->' header to refresh.")
Expand All @@ -136,12 +139,13 @@ def insert_at_marker(text: str, marker: str, addition: str) -> str:
scriv uses for release sections.
"""
marker_line = re.compile(
rf"^([ \t]*<!--\s*{re.escape(marker)}\s*-->[ \t]*)$", re.M
rf"^([ \t]*<!--\s*{re.escape(marker)}\s*-->[ \t]*)$",
re.M,
)
match = marker_line.search(text)
if not match:
raise AssemblyError(
f"Output file has no '<!-- {marker} -->' marker; refusing to guess where tasks belong."
f"No '<!-- {marker} -->' marker in the output file; refusing to guess where tasks belong.",
)
return text[: match.end()] + f"\n\n{addition}" + text[match.end() :]

Expand Down
Loading