Fix the configuration-reference generator - #766
Open
wbarnha wants to merge 1 commit into
Open
Conversation
`extra/tools/render_configuration_reference.py` generates
docs/includes/settingref.txt, which docs/userguide/settings.rst
includes. Nothing validates its output, so a bug there silently
corrupts the published configuration reference instead of failing
something. Three did, and together they made the output depend on which
interpreter ran `make configref` -- which is why regenerating produced a
tree-wide diff rather than a clean one.
## Docstring dedent, broken by Python 3.13
`normalize_indent` dedented by scanning for the first *indented* line
after the summary and stripping that much from every line. On 3.12 and
older that was the body indent, so it worked.
Python 3.13 strips the common leading whitespace from docstrings at
compile time. From then on the body arrives flush left, and the first
indented line the scan finds is the body of a `.. warning::` or
`.. note::` -- whose indent it then removed, so the content escaped the
directive and rendered as loose paragraphs instead of an admonition.
Replaced with `inspect.cleandoc`, which dedents by the *minimum* indent:
a no-op on an already-dedented docstring, and byte-identical output on
every supported interpreter. That also fixes an off-by-one in
`strip_space` (`i > n` where `i >= n` was meant), which is why directive
bodies in the committed reference sit at three spaces rather than four.
## `pathlib._local` on 3.13+
Types were referenced through `__module__`. 3.13 moved `pathlib.Path`
into `pathlib._local`, so the reference became
`:class:`~pathlib._local.Path``, which resolves nowhere -- and changed
depending on the interpreter. `public_module()` now walks up private
components and takes the shallowest package that still exposes the same
object.
## CLI options rendered one character at a time
Three settings declared `related_cli_options={"faust": "--datadir"}`,
a bare string where `Mapping[str, List[str]]` is declared. The renderer
iterates the value, so `--datadir` became nine separate options:
:option:`faust -`, :option:`faust -`, :option:`faust d`, ...
`Section.setting()` takes `**kwargs: Any`, so the declared type is
erased and mypy cannot catch it -- hence the test below rather than a
type fix alone.
## Tests
tests/unit/test_configref_renderer.py covers the normalization against
both docstring forms, the directive-body indent, the module reference,
and a smoke render of every real setting. It also asserts no setting
declares its CLI options as a bare string.
Verified in both directions: 6 of the 9 fail against the original
generator on 3.12 and on 3.13; all 9 pass after. The generator now
produces byte-identical output on 3.12, 3.13 and free-threaded 3.14.
## Not done here
The committed settingref.txt is deliberately left untouched, because
regenerating it needs two unrelated decisions first:
* it contains a hand-written "OAuth2 Authentication" block that exists
nowhere in the source docstrings, so regenerating would delete real
documentation. It belongs in `broker_credentials.__doc__`.
* `broker_client_id` defaults to `f"faust-{faust_version}"`, so the
rendered default embeds whichever version generated it -- the
committed file says `faust-0.8.9`, a dev tree renders
`faust-0.1.dev193+...`. Until that is symbolic the file cannot be
regenerated reproducibly, and no byte-exact CI drift check can work.
Worth knowing meanwhile: `python extra/tools/...` puts the script's own
directory on sys.path, not the repository root, so the generator renders
whichever faust is *installed*. With a non-editable install it silently
renders a stale copy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K8qT5E3rnSXvw7ibNLXrVr
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #766 +/- ##
==========================================
- Coverage 96.06% 96.05% -0.01%
==========================================
Files 103 103
Lines 11072 11081 +9
Branches 1191 1189 -2
==========================================
+ Hits 10636 10644 +8
Misses 345 345
- Partials 91 92 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
extra/tools/render_configuration_reference.pygeneratesdocs/includes/settingref.txt, whichdocs/userguide/settings.rstincludes. Nothing validates its output, so a bug there silently corrupts the published configuration reference instead of failing something. Three did — and together they made the output depend on which interpreter ranmake configref, which is why regenerating produced a tree-wide diff rather than a clean one.Docstring dedent, broken by Python 3.13
normalize_indentdedented by scanning for the first indented line after the summary and stripping that much from every line. On 3.12 and older that was the body indent, so it worked.Python 3.13 strips the common leading whitespace from docstrings at compile time. From then on the body arrives flush left, and the first indented line the scan finds is the body of a
.. warning::or.. note::— whose indent it then removed, so the content escaped the directive and rendered as loose paragraphs instead of an admonition:Replaced with
inspect.cleandoc, which dedents by the minimum indent: a no-op on an already-dedented docstring, and byte-identical output on every supported interpreter. That also fixes an off-by-one instrip_space(i > nwherei >= nwas meant), which is why directive bodies in the committed reference sit at three spaces rather than four.pathlib._localon 3.13+Types were referenced through
__module__. 3.13 movedpathlib.Pathintopathlib._local, so the reference became:class:~pathlib._local.Path`` — which resolves nowhere, and changed depending on the interpreter.public_module()now walks up private components and takes the shallowest package that still exposes the same object.CLI options rendered one character at a time
Three settings declared
related_cli_options={"faust": "--datadir"}— a bare string whereMapping[str, List[str]]is declared. The renderer iterates the value, so--datadirbecame nine separate options:Section.setting()takes**kwargs: Any, so the declared type is erased and mypy cannot catch it — hence a test rather than a type fix alone.Tests
tests/unit/test_configref_renderer.pycovers the normalization against both docstring forms, the directive-body indent, the module reference, a smoke render of every real setting, and asserts no setting declares its CLI options as a bare string.Verified in both directions: 6 of the 9 fail against the original generator on 3.12 and 3.13; all 9 pass after. The generator now produces byte-identical output on 3.12, 3.13 and free-threaded 3.14.
Full suite: 2216 passed.
mypy,verify_doc_defaults,flake8/black/isortall clean.Not done here
docs/includes/settingref.txtis deliberately left untouched, because regenerating it needs two unrelated decisions first:broker_credentials.__doc__.broker_client_iddefaults tof"faust-{faust_version}", so the rendered default embeds whichever version generated it — the committed file saysfaust-0.8.9, a dev tree rendersfaust-0.1.dev193+.... Until that is symbolic the file cannot be regenerated reproducibly, and no byte-exact CI drift check can work.Worth knowing meanwhile:
python extra/tools/...puts the script's own directory onsys.path, not the repository root, so the generator renders whichever faust is installed. With a non-editable install it silently renders a stale copy.Note
Touches
docs/includes/settingref.txt's generator but not the file, so it should not conflict with #762 — which adds a setting entry to that file by hand for the same reason described above.Generated by Claude Code