DOC: Auto-link symbol references in generated API docs#1823
Merged
romanlutz merged 7 commits intoJun 1, 2026
Conversation
When PR microsoft#1782 converted Sphinx reST roles to plain double-backticks under jupyter-book 2's MyST renderer, all the symbol cross-references in our docstrings stopped being clickable. This restores them without forcing contributors to learn MyST link syntax. Changes: * �uild_scripts/gen_api_md.py now emits an explicit, FQN-scoped MyST label before every class, function, and method heading (e.g. (api-pyrit_prompt_target-PromptTarget)=) and post-processes every docstring text, parameter description, return description, and raises description: backtick code spans whose contents unambiguously resolve to a PyRIT class, function, or method become MyST links to the right anchor. Ambiguous short names and fenced code blocks are left alone. The API index page now links each preview symbol to its anchor too. * Cleaned up 13 leftover Sphinx reST roles in pyrit/ that PR microsoft#1782 missed (cli_helpers, scorer_metrics, pyrit_scan, tree_of_attacks). * Added �uild_scripts/check_no_rest_roles.py plus a pre-commit hook so newly introduced :class: / :func: / :meth: / etc. roles are rejected before landing. * Updated the style guide to describe the auto-linker behaviour and point at the new pre-commit guard. * 21 new unit tests in ests/unit/build_scripts/ cover the rewriter (single/double backticks, Class.method, FQN, current-class context, ambiguous skip, fenced-block protection, existing-link idempotency, tilde/dot prefix) and the pre-commit guard. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two extra unit tests on the auto-linker integration path: * `test_process_docstring_text_protects_doctest_examples` pins the order I had to swap mid-implementation: `_escape_docstring_examples` must run before `_rewrite_symbol_refs` so a known PyRIT symbol appearing inside a `>>>` doctest example stays as raw text (otherwise the code sample would render as broken markdown). * `test_render_function_emits_anchor_and_links_docstring_fields` plus `test_render_function_uses_method_anchor_when_class_name_given` are end-to-end smoke tests on `render_function`: they assert the `(api-...)=` label is emitted with the right scoping (module vs. method) and that every docstring field (text, params, returns, raises) goes through the rewriter so a regression in any of those four code paths fails the build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
romanlutz
added a commit
to romanlutz/PyRIT
that referenced
this pull request
May 28, 2026
…icks The `check-no-rest-roles` pre-commit hook added in microsoft#1823 flags four `:meth:model_dump` / `:meth:model_validate` references in `pyrit/models/conversation_reference.py` and `pyrit/models/retry_event.py` that landed via PR microsoft#1769 before the hook existed. Replace them with plain double-backticks so the hook passes cleanly on this stacked branch and the deprecation notices render as readable code spans under MyST instead of literal `:meth: ame` text. `model_dump` / `model_validate` are Pydantic methods, not PyRIT API, so the auto-linker leaves them as plain code spans (correct: there is nothing in our docs to link them to). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
hannahwestra25
approved these changes
Jun 1, 2026
romanlutz
added a commit
to romanlutz/PyRIT
that referenced
this pull request
Jun 2, 2026
…kticks The typing modernization sweep in this PR rewrites `Optional[str]` to `str | None` in `pyrit/models/conversation_reference.py` and `pyrit/models/retry_event.py`. That puts both files in the changed-files set CI feeds to `pre-commit run --from-ref origin/main --to-ref HEAD`, which surfaces four pre-existing `:meth:` reST roles (landed via microsoft#1769 before the `check-no-rest-roles` hook from microsoft#1823 existed). Replace `:meth:model_dump` and `:meth:model_validate` with plain double-backticks so the hook passes. `model_dump` / `model_validate` are Pydantic methods, so the auto-linker in `build_scripts/gen_api_md.py` correctly leaves them as plain code spans. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closed
6 tasks
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.
Before / after
Same section —
pyrit.registry.AttackTechniqueRegistry.build_factory_from_specdocstring — in the rendered API page. Before, every symbol reference is a dead pink code span; after, the PyRIT class names are underlined, clickable MyST links that jump straight to the relevant module page.Before (
origin/main):After (this PR):
Why
When #1782 converted Sphinx reST roles (
:class:,:func:,:meth:, ...) to plain double-backticks under jupyter-book 2's MyST renderer, all the symbol cross-references in our docstrings stopped being clickable. Plain backticks are still the right human-readable default - contributors shouldn't have to learn MyST link syntax - but the rendered API pages have been a sea of un-navigable inline code spans ever since.This PR restores the cross-references at render time, so source stays clean.
What
1. Auto-linker in
build_scripts/gen_api_md.py(api-pyrit_prompt_target-PromptTarget)=. This avoids ambiguity where short names likeScorerorScorecollide across modules.Class.method, fully-qualified path).text/ parameter descriptions / returns / raises so backtick code spans whose contents unambiguously resolve to a PyRIT symbol become real MyST links -SeedPrompt->[`SeedPrompt`](#api-pyrit_models-SeedPrompt).Scorer),Class.method(PromptTarget.send_prompt_async), fully-qualified names (pyrit.models.SeedPrompt), tilde/dot-prefixed forms left over from reST conversions, and class-scoped method references (a baresend_prompt_asyncinsidePromptTarget's docstring links to the right method).2. Cleaned up the 13 leftover reST roles that #1782 missed
In
cli_helpers.py,scorer_metrics.py,pyrit_scan.py,tree_of_attacks.py. Replaced with plain double-backticks so the new auto-linker can take it from here.3. Pre-commit guard
build_scripts/check_no_rest_roles.py+ a newcheck-no-rest-roleslocal hook in.pre-commit-config.yamlreject any newly-introduced:class:/:func:/:meth:/:mod:/:attr:/:data:/:exc:/:obj:/:ref:/:py:*:role inpyrit/. Error message points contributors at the new convention.4. Style guide refresh
.github/instructions/style-guide.instructions.mdnow describes the auto-linker, mentions the guard, and explains what gets auto-linked vs. left as plain code-spans.Tests
24 new unit tests in
tests/unit/build_scripts/:test_gen_api_md.py(18 tests) covers anchor helpers, the symbol index (classes/functions/methods, private skipping, ambiguous duplicates), the rewriter (single/double backticks,Class.method, FQN, current-class context, ambiguous skip, unknown-name passthrough, fenced-block protection, idempotent existing-link handling, tilde/dot prefix, empty-text passthrough), the_process_docstring_textdoctest-fence ordering, andrender_functionend-to-end (anchor emission, all four docstring fields rewritten, method-scoped anchors withcurrent_classcontext).test_check_no_rest_roles.py(6 tests) covers the pre-commit guard CLI.All 8,096 unit tests pass. Pre-commit clean (ruff format, ruff check, ty type-check all green).
Validation
make docs-build(i.e.jupyter-book build --all --html --strict) succeeds.id="api-pyrit-prompt-target-prompttarget"and the cross-reference links resolve to the right headings (mystmd normalises labels to lowercase-kebab).jupytextextra keys,guttergrid option, the legacy-target warning inhf_aml_model_endpoint_guide.md) remain.Out of scope
Bases:,Re-exports, and module-level page labels - follow-up PR in flight.gen_api_md.pyworkaround entirely - waiting on upstream JB2 native API doc support (Add support for API documentation generation jupyter-book/mystmd#1259).