From 381b75dceefb976af2c03cf524cebe99a2468079 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 7 Sep 2026 20:01:32 +0000 Subject: [PATCH 1/2] Fail closed when manim.unsafe_unicode is not a YAML list The property already raised on a scalar, but only when validate or scene-spec-generate read it. Evaluate it in Config.from_yaml and require string list items, matching manim.scenes. Co-authored-by: jmjava --- milestones/README.md | 8 +++++--- milestones/manim-unsafe-unicode.md | 33 ++++++++++++++++++++++++++++++ milestones/validation-list-keys.md | 4 ++-- src/docgen/config.py | 17 ++++++++------- tests/test_config.py | 7 +++++++ 5 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 milestones/manim-unsafe-unicode.md diff --git a/milestones/README.md b/milestones/README.md index 5453bcf..e02ea8b 100644 --- a/milestones/README.md +++ b/milestones/README.md @@ -5,11 +5,13 @@ repositories that install `docgen` and maintain their own demo bundle. The library no longer ships an in-repo dogfood; consumers are the integration test of record. -**Active:** **[validation-list-keys.md](validation-list-keys.md)** — -`validation.ocr.error_patterns`, `av_sync.visual_types`, and narration-lint -deny pattern lists must be YAML lists, not scalars. +**Active:** **[manim-unsafe-unicode.md](manim-unsafe-unicode.md)** — +`manim.unsafe_unicode` must be a YAML list at config load, not a scalar. **Shipped:** +- **[validation-list-keys.md](validation-list-keys.md)** — + `validation.ocr.error_patterns`, `av_sync.visual_types`, and narration-lint + deny pattern lists must be YAML lists (#95). - **[wizard-exclude-lists.md](wizard-exclude-lists.md)** — `wizard.exclude_patterns` / `scan_extensions` must be string lists (#94). - **[timestamps-merge-stems.md](timestamps-merge-stems.md)** — CLI `timestamps` diff --git a/milestones/manim-unsafe-unicode.md b/milestones/manim-unsafe-unicode.md new file mode 100644 index 0000000..49914c7 --- /dev/null +++ b/milestones/manim-unsafe-unicode.md @@ -0,0 +1,33 @@ +# Milestone: `manim.unsafe_unicode` must be a list at config load + +**Status:** Active +**PR:** pending +**Depends on:** `milestones/validation-list-keys.md` (PR #95), +`milestones/config-mapping-keys.md` (PR #83) + +## Problem + +`manim.unsafe_unicode` as a YAML string already raised `ConfigError` when the +property was **read** (validate / scene-spec-generate). `Config.from_yaml` did +not touch it, so `yaml-generate`, `tts`, and other commands could load a bad +file. A string would also have been iterated as characters inside unicode lint +if anything called the property after a bypass. + +## Goal + +Evaluate `manim_unsafe_unicode` during `Config.from_yaml` (same as +`manim.scenes`). Use `string_list_block` so items must be YAML strings. + +## Done when + +- [x] `manim.unsafe_unicode` if present must be a YAML list of strings. +- [x] Missing / null still uses the built-in Pango fallback character list. +- [x] Empty list still disables the unicode lint (`[]`). +- [x] Test for a string value at `Config.from_yaml`. +- [ ] `ruff check src/ tests/` +- [ ] `pytest tests/` +- [ ] `docgen benchmark` (no clock change) + +## Out of scope + +- The default character list itself is unchanged. diff --git a/milestones/validation-list-keys.md b/milestones/validation-list-keys.md index df2965e..a9a24d5 100644 --- a/milestones/validation-list-keys.md +++ b/milestones/validation-list-keys.md @@ -1,7 +1,7 @@ # Milestone: validation list keys must not be scalars -**Status:** Active -**PR:** pending +**Status:** Shipped +**PR:** #95 **Depends on:** `milestones/wizard-exclude-lists.md` (PR #94), `milestones/config-mapping-keys.md` (PR #83) diff --git a/src/docgen/config.py b/src/docgen/config.py index 87d0be4..283aa7b 100644 --- a/src/docgen/config.py +++ b/src/docgen/config.py @@ -206,6 +206,7 @@ def __post_init__(self) -> None: # List-valued keys: a string must not be iterated as characters. _ = self.segments_all _ = self.manim_scenes + _ = self.manim_unsafe_unicode concat = self._block("concat") src = self._source_label() for name, segs in concat.items(): @@ -538,15 +539,13 @@ def manim_unsafe_unicode(self) -> list[str]: "\u2260", "\u2264", "\u2265", "\u2014", "\u2013", "\u2018", "\u2019", "\u201c", "\u201d", "\u2022", "\u2026"] - val = self._block("manim").get("unsafe_unicode", default) - if val is None: - return list(default) - if not isinstance(val, list): - raise ConfigError( - f"{self._source_label()}: manim.unsafe_unicode must be a YAML list, " - f"not {type(val).__name__}" - ) - return [str(x) for x in val] + return string_list_block( + self._block("manim"), + "unsafe_unicode", + fallback=default, + label="manim.unsafe_unicode", + source=self._source_label(), + ) # -- Compose ---------------------------------------------------------------- diff --git a/tests/test_config.py b/tests/test_config.py index 3574aa5..cdd95f0 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -371,3 +371,10 @@ def test_from_yaml_string_post_tts_deny_patterns_raises(tmp_path: Path) -> None: ConfigError, match="validation.narration_lint.post_tts_deny_patterns must be a YAML list" ): Config.from_yaml(p) + + +def test_from_yaml_string_manim_unsafe_unicode_raises(tmp_path: Path) -> None: + p = tmp_path / "docgen.yaml" + p.write_text("manim:\n unsafe_unicode: \"\\u2192\"\n", encoding="utf-8") + with pytest.raises(ConfigError, match="manim.unsafe_unicode must be a YAML list"): + Config.from_yaml(p) From c051fea53f4088c3b836b6ee39f594f80e542032 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 7 Sep 2026 20:02:17 +0000 Subject: [PATCH 2/2] Mark manim-unsafe-unicode milestone gates as run Local ruff, pytest, and docgen benchmark are green on this branch. Co-authored-by: jmjava --- milestones/manim-unsafe-unicode.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/milestones/manim-unsafe-unicode.md b/milestones/manim-unsafe-unicode.md index 49914c7..0270e99 100644 --- a/milestones/manim-unsafe-unicode.md +++ b/milestones/manim-unsafe-unicode.md @@ -24,9 +24,9 @@ Evaluate `manim_unsafe_unicode` during `Config.from_yaml` (same as - [x] Missing / null still uses the built-in Pango fallback character list. - [x] Empty list still disables the unicode lint (`[]`). - [x] Test for a string value at `Config.from_yaml`. -- [ ] `ruff check src/ tests/` -- [ ] `pytest tests/` -- [ ] `docgen benchmark` (no clock change) +- [x] `ruff check src/ tests/` +- [x] `pytest tests/` +- [x] `docgen benchmark` (no clock change) ## Out of scope