Autodoc design system: 3-tier architecture, shared layout + typehints#18
Merged
Autodoc design system: 3-tier architecture, shared layout + typehints#18
Conversation
why: out/ was a repo-local symlink tree mirroring testpaths, used as a workaround for an upstream pytest capture-teardown bug. Removing it from tracked history (filter-repo) requires a gitignore so it cannot be recommitted by accident if the validator mirror is recreated locally. what: - Add out/ to .gitignore under a new "Repo-local pytest mirror" section
…arameter folding why: Large autodoc entries (90+ kwargs) need semantic regions for independent styling and progressive disclosure. Parameters repeated 3x due to autoclass_content="both" + autodoc_class_signature="separated". what: - Fix DEFAULT_AUTOCLASS_CONTENT from "both" to "class" (eliminates 3x params) - Two custom nodes: gal_region (contiguous content wrappers) and gal_fold (<details>/<summary> for large field lists) - doctree-resolved handler at priority 600 (after api-style at 500) - Order-preserving contiguous chunking: narrative / fields / members - Fold large field_list in desc_content, not desc_signature - Descendant CSS selectors (survive <details> wrapping) - JS hash-based auto-expand for <details> ancestors - Tests for nodes, classification, wrapping, and folding
why: Sphinx's DocFieldTransformer collapses params into a single field with a bullet_list of list_items. The fold logic counted field nodes (always 1-3) instead of list_items (the actual param count), so the fold never triggered. what: - Add _count_field_entries() that counts list_items inside collapsed bullet_list fields plus standalone field nodes - Enable extension in docs/conf.py with gal_enabled=True - Add gal_demo_api.py demo with LayoutDemo class (13 params) - Add live demo section to sphinx-autodoc-layout.md - Verify: docs build shows <details class="gal-fold"> wrapping params
why: Large signatures (13+ params) overwhelm the header. The user wants collapsed: __init__(host, [...]) that expands to show each param on its own indented line. what: - Add gal_sig_fold node wrapping desc_parameterlist in <details> - Summary shows first param + [...]; open shows full list one-per-line - CSS: font-size:0 hides commas, block em.sig-param for indentation - Parens from desc_parameterlist visitor stay intact (no duplication) - Fix _count_field_entries for Sphinx collapsed bullet_list fields
…m indent why: Raw comma text nodes and flex centering broke the expanded gal-sig-fold display; param lines used heavy 2rem indent. what: - Hide comma text nodes via font-size on open details; restore em/sig-paren - Trailing commas via ::after; last param has none - dt:has(open) align-items flex-start for api-style flex dt - Use display block on open details; reduce param margin-left to 1rem
why: Preserve Sphinx autodoc semantics while exposing a stable, customizable DOM contract and letting long signatures expand onto a real second row. what: - rebuild managed Python autodoc entries into explicit api-* header, content, and footer components with custom inline signature disclosure - add layout integration coverage for parameter regions, member nesting, badge and source placement, and hash-driven expansion behavior - align pytest fixture warning paths with both caplog-based unit tests and Sphinx integration warning streams
why: We need focused snapshot tests for rendered autodoc HTML, and the user asked for the dependency to land in its own isolated commit. what: - Add Syrupy to the dev dependency group - Refresh uv.lock for the new snapshot testing dependency
why: Expanded folded signatures needed cleaner formatting, explicit collapse affordances, and stronger regression coverage to keep the new API layout maintainable. what: - Rework folded signature output around Sphinx's native multiline parameter HTML with typed annotation recovery - Add explicit collapse controls and CSS fixes for single-indent multiline rendering - Cover the rendered API header with integration checks and Syrupy-backed HTML snapshots
why: Collapsed folded signatures were still pinned to the top of the padded dt card because the centering state lived on the inner layout row instead of the real desc_signature shell. what: - move managed signature expansion state onto desc_signature/dt and sync it in JS - render managed dt tags directly so custom header attributes reach the HTML output - retarget CSS, integration coverage, and snapshots to the dt-level header model
why: Integration tests were rebuilding the same synthetic Sphinx projects dozens of times and dominated the suite runtime. what: - add a typed test-only Sphinx scenario cache helper with shared-build and copied-source modes - reuse cached scenario builds in layout and pytest-fixture integration tests - add regression tests covering cache reuse, scenario key changes, and source-tree isolation
why: Keep local feedback focused on doctree and snapshot contracts while reserving full Sphinx builds for explicit end-to-end output checks. what: - split synthetic Sphinx scenario coverage into doctree-first and minimal E2E lanes - add typed snapshot and scenario helpers plus fast local test commands and docs - move non-builder scenario cache tests out of integration and fix remaining typing issues
why: Local test runs were dominated by pytest tmp_path retention and numbering overhead rather than real test work. what: - update just recipes to use fixed repo-local basetemps and no tmp retention - document the optimized local runner strategy and known pytest capture bugs - trim a few unnecessary tmp_path usages in snapshot, font, and scenario tests
why: Keep the Sphinx-heavy test lane focused on true builder-facing contracts while documenting where runtime still goes in the current environment. what: - extract pure pytest-fixture helpers for generated directive text, fixture-index table selection, and doc-pytest-plugin section assembly - replace heavier synthetic Sphinx assertions with narrower helper and doctree tests, and update snapshots to match the slimmer contract surface - refresh the performance analysis note and local runner docs with current benchmark data, remaining E2E hotspots, and known pytest runner anomalies
why: The earlier analysis over-weighted deselected fast lanes and hid where the real full-suite time still goes. We also still had a few synthetic Sphinx tests rebuilding per test when module-scoped shared results would cover the same contracts. what: - update notes/test-analysis.md with full-suite benchmarks, cProfile findings, remaining slow tests, and current runner anomalies - remove redundant pytest ignore filters and document fast local loops as local-only diagnostics instead of coverage baselines - share layout and pytest-fixture Sphinx scenarios via module-scoped cache roots and a layout conftest to reduce unnecessary synthetic harnessing
why: Keep the performance write-up grounded in full-suite coverage and trim one more unnecessary temp-dir hotspot. what: - refresh notes/test-analysis.md with full-suite benchmarks, cProfile findings, and runner anomaly details - document the pytest tempdir and capture costs separately from real Sphinx builder time - reuse a module-scoped temp root in tests/test_sphinx_scenarios.py to reduce needless tmp_path churn
why: Keep full coverage intact while cutting over-harnessed Sphinx tests and recording where suite time is really going. what: - replace remaining directive/order/filter checks with pure helper or smaller doctree tests - reuse shared layout and scenario builds more aggressively with session or module cache roots - update test-analysis with full-suite timings, profile findings, and the external pytest runner repro
why: The raw full suite was still paying avoidable pytest temp-path overhead even after the Sphinx harness audit, and doctests were still creating fresh tmp paths without adding coverage. what: - switch doctest namespace injection to a session-scoped shared tmp path - update test-analysis notes with the new full-suite benchmarks and profile data - document that the remaining multi-second tests are mostly real builder-facing contracts
why: Reduce synthetic Sphinx setup cost without hiding coverage, and refresh the suite analysis around real full-suite behavior. what: - add shared session-scoped pytest-fixture scenario roots for doctree, html, and type-checking tests - replace one heavy MyST autofixtures snapshot with a smaller contract-focused smoke - update the test performance note with current benchmarks, slow-test causes, and runner bug analysis
why: Reduce full-suite runtime by removing unnecessary synthetic fixture surface from smoke tests while preserving real emitted-output and xref coverage. what: - shrink pytest-fixture HTML, text, MyST, and fixture-index smoke scenarios to the minimum fixture set needed for each contract - narrow scenario-cache smokes to a plain-page Sphinx scenario instead of paying for autodoc imports - refresh notes/test-analysis.md with the new full-suite baselines, slow-test table, and updated profiling findings
why: One more repeated dummy-builder scenario was still paying for separate setup despite testing the same reduced fixture surface. what: - share one MyST dummy-builder result across the doc-pytest-plugin and autofixtures smokes - keep the canonical RST doc-pytest-plugin snapshot on the reduced smoke fixture source - refresh notes/test-analysis.md with current serial full-suite timings, slow tests, and profile data
why: Keep full builder-backed coverage while removing the last smoke-only Sphinx work that was larger than the contracts under test. what: - reduce the pytest-fixture html and text smoke pages to the minimal emitted output surface they assert - refresh notes/test-analysis.md with current full-suite benchmarks, profile findings, and runner-bug evidence
why: Reduce unnecessary Sphinx harness cost without hiding failures and keep the required validator running the real suite. what: - rewrite the TYPE_CHECKING alias metadata smoke as a typed helper-level registration test - remove the unused shared type-checking Sphinx scenario fixture and refresh the runtime analysis note - add the repo-local pytest and out-path mitigation for the upstream-style capture teardown bug
why: Make Python-domain autodoc output easier to customize while reducing validation cost without hiding failures. what: - add a typed api_slot contract and make sphinx-autodoc-layout own final header/body composition - switch api-style and pytest-fixtures to structured badge/source slots and auto-load layout - replace heavy layout header snapshots with doctree snapshots and refresh test/runtime analysis
…ackages why: Centralize object-entry composition so badges, headers, and body regions can be reused across the autodoc packages without raw HTML mutation or extra full-build coverage. what: - add shared layout profiles and parse helpers for py, std, and rst entries - move autodoc-sphinx and autodoc-docutils onto slot-based layout badges - refactor FastMCP cards onto shared api regions and add lighter tests
why: Consolidate the remaining slot-injection duplication, validate a future FastMCP desc migration safely, and keep the runtime analysis aligned with the actual post-refactor suite. what: - add a shared layout slot helper and move producer packages onto it - add a test-only FastMCP desc prototype plus lighter doctree and snapshot coverage - refresh the autodoc/runtime analysis with second-wave benchmarks and profile data
why: FastMCP lacked rendered output demos and the autodoc package pages had drifted into inconsistent documentation patterns. what: - add a typed FastMCP docs demo module and wire FastMCP into the docs build - standardize autodoc package pages around config, usage examples, and live demos - add focused docs parity tests plus a cached FastMCP page render smoke
…ured section passthrough why: Centralize the remaining duplicated badge construction and body-section building across all autodoc producer packages so future changes land in one place. what: - add BadgeSpec dataclass + build_badge_from_spec/build_badge_group_from_specs to sphinx-autodoc-badges - add _sections.py (ApiFactRow, build_api_facts_section, build_api_table_section) to sphinx-autodoc-layout - add _STRUCTURED_SECTION_NAMES passthrough in _wrap_content_runs so pre-built api-facts/api-options nodes survive the transform - migrate all producer _badges.py files onto BadgeSpec (docutils, fastmcp, pytest-fixtures, sphinx) - add _normalize_directive_nodes / _normalize_role_nodes to autodoc-docutils using shared sections - move confval type/default/registered-by facts into build_api_facts_section in autodoc-sphinx - replace inline returns_para in fastmcp with build_api_facts_section - add _wrap_fixture_field_lists in pytest-fixtures transforms to wrap field lists in api-facts/api-parameters - update all integration tests to assert api-facts and api-options sections are present - add test_wrap_preserves_prebuilt_fact_sections, test_build_badge_from_spec, test_build_badge_group_from_specs - update fixture doctree snapshots for sab-badge-group class and api-facts wrapping - update test-analysis.md with wave 3 suite status and benchmark data
…ucer-level doctree tests why: rst:directive, rst:role, and confval entries had the correct api-container HTML structure but no visual card styling; Furo only cards dl.py.* entries so non-Python domain entries appeared flat. Producer behavior also lacked targeted unit tests. what: - add dl.api-container:not(.py) card rules to layout.css (border, border-radius, box-shadow, header background, hover, nested lighter treatment) — matches api_style.css dl.py values - CSS lives in layout.css so any project using sphinx-autodoc-layout gets card styling regardless of whether sphinx-autodoc-api-style is also loaded - add tests/ext/autodoc_docutils/test_doctree.py: 9 unit tests for _normalize_directive_nodes and _normalize_role_nodes verifying api-facts labels, fact values, option extraction, and cross-domain isolation — no Sphinx app required - add tests/ext/autodoc_sphinx/test_doctree.py: 11 unit tests for _config_fact_rows verifying Type/Default/Registered-by rows, complex-default literal_block path, simple-default paragraph path, and ApiFactRow type conformance - update notes/test-analysis.md with wave 4 diagnosis, fix, docs rebuild note, and benchmark
…ehavior why: Three visual bugs introduced after the api-container containerization: - dt.api-header had align-items:center without display:flex so centering was a no-op - rst/confval badge type classes had no color definitions (transparent background) - api-link permalink was always visible because Furo only hides direct dt children what: - add display:flex to dl.api-container > dt.api-header (both normal and expanded variants) so div.api-layout is vertically centered within the padded dt - add visibility:hidden to .api-link and visibility:visible on dt:hover and :focus-visible to match Furo's headerlink hover behavior for the nested permalink - create sphinx-autodoc-sphinx/_static/css/sphinx_autodoc_sphinx.css with amber tokens for sas-badge--type (config badge) and gray tokens for sas-badge--rebuild (outline badge) - create sphinx-autodoc-docutils/_static/css/sphinx_autodoc_docutils.css with violet tokens for sadoc-badge--type (directive/role/option badges) - register new CSS files in setup() for both packages; update doctest FakeApp - update test_css.py assertions to expect display:flex in dt.api-header rules
…string why: aa664ff renamed SAB.obj_type()'s returned class from sab-type-* to gp-sphinx-badge--type-*, but this test's docstring kept the old name. Assertions already check the new name, so the docstring was the sole remaining stale reference in this file. what: - Replace "returns sab-type-* class" with "returns gp-sphinx-badge--type-* class" on one docstring line - No behavioural change; docstring-only edit
why: AGENTS.md requires "every parameter and -> None must be typed" on test functions. Four tests added in the doctree-test extraction passed snapshot_doctree / snapshot_warnings unannotated, while the adjacent test_snapshots.py and test_layout/ files already follow the pattern `snapshot_doctree: t.Callable[..., None]`. The fixtures declare that exact return type in tests/_snapshots.py, so the annotation is a straight alignment with the fixture contract and the house style. what: - Annotate snapshot_doctree / snapshot_warnings parameters as t.Callable[..., None] on 4 test functions: test_default_fixture_post_transform_snapshot, test_dependency_rendering_snapshot, test_warning_and_manual_option_snapshot, test_doc_pytest_plugin_rst_snapshot. - No behavioural change; purely annotation work.
why: AGENTS.md's Test Level Hierarchy defines "Sphinx integration" as any test that "must verify actual HTML output or Sphinx event wiring". Every test in this file runs a real Sphinx build (dummy builder for doctree-level assertions) via `build_shared_sphinx_result`, which exercises full event wiring (directives register, transforms run, domain data populates, warnings emit). None were marked, so `pytest -m integration` and `-m "not integration"` selectors didn't reflect the actual test shape. what: - Mark all 13 tests in test_sphinx_pytest_fixtures_doctree.py with @pytest.mark.integration: the 9 that call build_fixture_result inline (manual, dependency, warning/manual-option, autofixture, autofixtures_smoke, short_name, plugin RST, plugin MyST, autofixtures MyST, lint-level) plus the 4 that consume the module-scoped default_dummy_result / autofixtures_usage_result / myst_smoke_result fixtures. - No behavioural change; markers only. `just test` still runs all 944 tests; `pytest -m integration` now correctly includes these.
…ture muting
why: The `:deprecated:` option on the `py:fixture` directive appends
SAB.STATE_DEPRECATED ("gp-sphinx-badge--state-deprecated") to the
parent `desc` container so CSS can dim the entry. Before the aa664ff
rename the muting rule lived in pytest-fixtures' own CSS
(dl.py.fixture.spf-deprecated > dt). After the rename the
equivalent rule only exists in sphinx-autodoc-api-style's CSS at
the broader `dl.py.gp-sphinx-badge--state-deprecated > dt` scope.
That is fine inside the gp-sphinx bundle, but pytest-fixtures'
pyproject does not depend on sphinx-autodoc-api-style — users who
install pytest-fixtures standalone (or without the api-style
extension enabled) lose the visual signal silently.
what:
- Add a fixture-scoped rule to sphinx_autodoc_pytest_fixtures.css:
`dl.py.fixture.gp-sphinx-badge--state-deprecated > dt { opacity: 0.7 }`.
Co-exists harmlessly with api-style's broader rule (same opacity,
narrower selector); only fires when pytest-fixtures' directive has
flagged the container.
- Inline comment records the coupling with api-style and the
standalone-install rationale.
- No change to extension code; the SAB.STATE_DEPRECATED application
in _directives.py already drives this selector.
why: The aa664ff CSS namespace rename turned SAB.UNDERLINE into a silent alias for SAB.UNDERLINE_SOLID — both constants now hold "gp-sphinx-badge--underline-solid". Before the rename UNDERLINE held the distinct "sab-badge--underline" class (plain underline), but that CSS rule and its distinct value were dropped in the rename. The aliased constant has zero call sites (confirmed via `git grep 'SAB\.UNDERLINE\b'` — only UNDERLINE_SOLID, UNDERLINE_DOTTED, and NO_UNDERLINE are referenced, including the `sab_demo.py` documentation label at line 270). Keeping the alias would silently mislead any future caller who picked it by name expecting plain underline. what: - Remove the redundant `UNDERLINE = "gp-sphinx-badge--underline-solid"` line from the SAB container; the underline axis now exposes only the three distinct values NO_UNDERLINE, UNDERLINE_DOTTED, UNDERLINE_SOLID. - No caller or CSS change required.
why: The per-package smoke job in tests.yml matrices across every publishable workspace package so each wheel installs cleanly and sphinx-build succeeds against its docs. The matrix was missing the four packages added or renamed most recently — sphinx-autodoc-fastmcp, sphinx-autodoc-typehints-gp, sphinx-ux-badges, and sphinx-ux-autodoc-layout — so CI was silently skipping their install and smoke verification on every push. what: - Add the four missing package slugs to the smoke matrix, completing coverage for every entry in packages/. - No job logic change; smoke job reuses the existing install + docs build step sequence.
… srcs why: AGENTS.md requires every function and method to have working doctests (no # doctest: +SKIP, no code-block workarounds). That rule was only being enforced for six of the eleven workspace packages because testpaths omitted the others. Adding them turns the pytest run into the authoritative doctest gate for the full workspace — currently lifting the suite from 944 to 1099 collected items with no failures. what: - Add packages/sphinx-autodoc-argparse/src, autodoc-docutils/src, autodoc-pytest-fixtures/src, autodoc-typehints-gp/src, ux-autodoc-layout/src, ux-badges/src to [tool.pytest.ini_options] testpaths. - Reorder the list alphabetically within the sphinx-autodoc-* / sphinx-ux-* groups so future additions land in an obvious spot.
…e install args
why: smoke_sphinx_autodoc_typehints_gp passed
f"sphinx {dist_dir}/sphinx_autodoc_typehints_gp-{version}-py3-none-any.whl"
as a single positional to _install_into_venv. That helper is
variadic (*requirements) and forwards each arg as its own token
to uv pip install, so the concatenated string became one
requirement with a literal space in the name — uv would reject it
as a syntactically invalid requirement. Every other smoke_* in this
module already uses the _target_wheel_path() helper; this one was
an oversight.
what:
- Replace the f-string with two positional arguments: "sphinx" and
_target_wheel_path(dist_dir, "sphinx-autodoc-typehints-gp").
- Matches the idiom used by the other smoke_* functions in the
same file.
…loor why: Record the breaking and feature-level shifts introduced by the autodoc-improvements branch so downstream alpha-testers can understand what changed before the next 0.0.1-series release cut. Kept terse — the package is still pre-1.0 and entries describe the net shipped result, not per-commit internals. what: - Add a new "Breaking changes" section covering the five package renames, the Sphinx 8.1 floor bump, and the gp-sphinx-* CSS namespace unification. - Append three bullets to the existing "Features" section: the three-tier design system restructuring, the new sphinx-ux-autodoc-layout package, and the new sphinx-autodoc-typehints-gp package.
why: The aa664ff namespace-unification commit retired six opaque per-package CSS prefixes (sab-, smf-, spf-, api-, gas-, gal-) in favour of a single gp-sphinx-* two-tier BEM root. Writing the convention into AGENTS.md prevents the next package from inventing another prefix and pays forward the time spent on this refactor. what: - Add a new "CSS Standards" section to AGENTS.md between "Testing Strategy" and "Coding Standards" listing the two-tier BEM rule, the modifier axis pattern, the custom-property namespace mirror, and the chained-selector 0,3,0 specificity convention. - Names Furo-owned variables as explicitly out of scope so the rule does not overreach.
…ests
why: The original wording ("Must verify actual HTML output or Sphinx
event wiring") left room to argue that buildername="dummy" tests
aren't really integration. During this branch's review, 13 such
tests were authored without @pytest.mark.integration because
"dummy" sounded lightweight enough to skip the marker. Tightening
the rule closes the loophole — if the test instantiates a Sphinx
app, it's integration, regardless of builder.
what:
- Rewrite the Sphinx-integration row of the Test Level Hierarchy
table in AGENTS.md to name build_shared_sphinx_result /
build_isolated_sphinx_result explicitly and call out the
dummy-builder case so future authors don't have to re-litigate
it.
why: The STATE_DEPRECATED fixture-muting regression on this branch was a stealth cross-package CSS dep — sphinx-autodoc-pytest-fixtures emitted gp-sphinx-badge--state-deprecated on fixture containers, but the muting rule only existed in sphinx-autodoc-api-style's CSS. Standalone installs of pytest-fixtures lost the visual signal silently. Writing the rule down prevents the next cross-package selector from slipping in unnoticed. what: - Add a "Package CSS self-containment" subsection under Code Architecture. States the principle (each package's CSS styles every class that package's Python emits) and draws the reuse-vs-dependence distinction so shared classes like gp-sphinx-badge stay legitimate while sibling-package CSS dependencies do not.
…project
why: twine check on the built wheel and sdist emitted
"long_description_content_type missing" and "long_description
missing" warnings — the only workspace package doing so. The
release.yml pipeline runs `twine check dist/*` after building every
publishable package; a CI step that escalates warnings to failures
(or a downstream tool that does) would block the next tag push.
Every sibling pyproject declares `readme = "README.md"` and
`authors = [...]`; this one was the outlier.
what:
- Add `readme = "README.md"` to [project] (README.md already exists
alongside pyproject.toml, so the reference resolves without any
file move).
- Add `authors = [{name = "Tony Narlock", email = "tony@git-pull.com"}]`
to match the sibling pattern.
- Verified by rebuilding the package and re-running twine check;
output now reads PASSED (previously PASSED with warnings).
why: pyproject.toml already declares `Typing :: Typed` in classifiers, but the PEP 561 marker file was never created — so downstream mypy / pyright runs skipped the package's inline annotations and treated imported symbols as Any. The classifier became aspirational without the file. Every other workspace package ships py.typed alongside its source; this was the outlier. what: - Add an empty py.typed alongside src/sphinx_autodoc_typehints_gp/ __init__.py. hatchling's wheel.packages setting includes it automatically (verified by unzipping the rebuilt wheel and confirming sphinx_autodoc_typehints_gp/py.typed is present). - No code or pyproject changes needed; the classifier is now truthful.
why: sphinx-autodoc-argparse, sphinx-fonts, and sphinx-gp-theme carried `Development Status :: 4 - Beta` while the remaining nine workspace packages were at `3 - Alpha`. The whole workspace publishes lockstep at 0.0.1a7 — a pre-release alpha version — so the three Beta outliers misrepresent their actual readiness to downstream consumers browsing PyPI. Since we release-gate all twelve packages together, their classifier story should line up. what: - Change `Development Status :: 4 - Beta` → `3 - Alpha` in the three outlier pyproject.toml files. - No functional or metadata-otherwise change; twine check still passes and the lockstep version gate is untouched.
…olding
why: The existing std:cmdoption wiring gives us `:option:` xrefs but
no argparse-specific namespace, no program-scoped option keys, no
per-domain indices, and no `:argparse:subcommand:` / `:argparse:positional:`
roles. Sphinx's Domain API exists for exactly this case — a
cohesive vocabulary for a class of documentation objects. This
commit lays down the scaffolding: domain class, four ObjTypes
(program / option / subcommand / positional), four XRefRoles, two
auto-generated indices (programs, options), and parallel-safe env
lifecycle hooks. Nothing is wired into setup() yet — deliberately,
so this change cannot alter any build and remains reviewable.
what:
- Add packages/sphinx-autodoc-argparse/src/sphinx_autodoc_argparse/
domain.py with:
* PROGRAM / OPTION / SUBCOMMAND / POSITIONAL module-level name
constants and an OBJECT_TYPES tuple for iteration.
* ArgparseProgramsIndex (alphabetical) and ArgparseOptionsIndex
(grouped by program) Index subclasses.
* ArgparseDomain with name="argparse", label="Argparse CLI",
data_version=0, initial_data={programs, options, subcommands,
positionals}, and typed property accessors for each table.
* note_program / note_option / note_subcommand / note_positional
helpers for renderer use.
* clear_doc / merge_domaindata / resolve_xref / resolve_any_xref /
get_objects implementing the parallel-safe env contract modelled
on sphinx.domains.rst.ReSTDomain.
* _lookup private helper supporting both "program name" whitespace-
joined and bare-name target forms.
* Module-level docstring + class/function-level doctests verifying
name / label / data_version / object-type registration.
- No change to setup(), renderer.py, or any other file. 1103 tests
pass (baseline 1099 + 4 new doctests from the scaffolding).
why: E1 added the ArgparseDomain scaffolding but did not register it.
Wire it now, before add_directive("argparse", ...), so every Sphinx
build instantiates the domain, makes the :argparse:program: /
:argparse:option: / :argparse:subcommand: / :argparse:positional:
roles discoverable, and exposes the two auto-generated index pages
(argparse-programsindex, argparse-optionsindex). No object is
registered yet, so xrefs resolve to None and indices render empty —
E3 adds the dual-emit hooks that actually populate the domain.
what:
- Import ArgparseDomain in the package __init__.
- Call app.add_domain(ArgparseDomain) at the top of the
registration block in setup(), with a comment pointing to the
dual-emit relationship with std:cmdoption.
- 1103 tests still pass — no behavioural change because the domain
tables are empty at build time.
…ubcommands, positionals why: Now that E1 defined ArgparseDomain and E2 registered it, the renderer needs to populate it. Continue emitting to std:cmdoption (so downstream :option: / intersphinx keeps working) AND record every program, option, subcommand, and positional with the new domain so :argparse:* xrefs resolve and the two indices render real content. Positionals and options are distinguished by name prefix: names starting with "-" are options, anything else is a positional (standard argparse convention). what: - Rename _register_option -> _register_argument and rewrite to dual-emit: std_domain.add_program_option (existing) + either argparse_domain.note_option or note_positional based on the leading-dash test. - Add _register_program helper; call it from render() when a program name is present. Anchor slug is `argparse-<prog-slug>` to match the existing argparse_program HTML visitor convention. - Add _register_subcommand helper; call it from render_subcommand() for every nested subcommand under a parent_prog. Anchor slug is `argparse-<parent-prog-slug>-<subcmd>`. - Update the in-renderer call site (render_argument) to use the renamed _register_argument. - Add doctest examples for all three new helpers showing the no-op path when env is absent. - 1105 tests pass (was 1103 + 2 new doctests). Snapshot .ambr files unchanged — the domain writes metadata only, not rendered HTML.
…dices, xref resolution
why: The ArgparseDomain scaffolding (E1), wiring (E2), and renderer
dual-emit (E3) landed without explicit test coverage. Lock in the
contract now so future refactors get early signal when something
regresses — and demonstrate end-to-end resolution once a real
Sphinx build runs the full .. argparse:: pipeline.
As a side effect, the existing test_option_xrefs_resolve_without_warnings
filter in test_domain_integration.py had to be narrowed: the earlier
"option" substring match false-matched the `desc_optional` node-class
re-registration noise that Sphinx emits when another test runs a
Sphinx build earlier in the same process. The new filter targets
actual xref-resolution failure strings.
what:
- Add tests/ext/autodoc_argparse/test_domain.py with 18 cases across
three groups:
* Unit tests (note_program / note_option / note_subcommand /
note_positional, clear_doc, merge_domaindata including the
"ignore entries outside docnames" path, get_objects emission).
* Lookup tests (_lookup on program, whitespace-joined option
target, bare option fallback, unknown objtype).
* Index tests (ArgparseProgramsIndex alphabetisation,
ArgparseOptionsIndex grouping by program, docnames filter).
* Two @pytest.mark.integration tests that build a synthetic
Sphinx project via the .. argparse:: directive and assert the
domain's data dicts are populated and resolve_xref returns a
real refnode.
- Narrow the warning filter in
test_domain_integration.py::test_option_xrefs_resolve_without_warnings
to "undefined label" / "unknown option" /
"reference target not found", documenting the change inline so the
choice of substrings is explicit.
- All existing tests pass; new count 1123 (+18).
…:: Domain why: E1-E4 landed a real ArgparseDomain subclass with four ObjTypes, four XRefRoles, two auto-generated indices, and parallel-safe env handling. The classifier is now truthful: PyPI users searching for `Framework :: Sphinx :: Domain` will find a package that does ship an actual domain, not just a domain-themed extension. what: - Add `Framework :: Sphinx :: Domain` to the classifier list in packages/sphinx-autodoc-argparse/pyproject.toml, between the bare `Framework :: Sphinx` and `Framework :: Sphinx :: Extension` rows. - Rebuild the wheel + sdist and confirm twine check PASSES cleanly (same as before; the classifier is a known Trove entry).
…s tier why: With E1-E5 landed, sphinx-autodoc-argparse now ships a real Sphinx domain (ArgparseDomain) — programs, options, subcommands, positionals, two auto-generated indices, full resolve_xref coverage. Its home on the tier map is now tier 2 alongside the other domain extensions, not tier 3 with the theme and fonts. Update the tier narrative on both the architecture and packages index pages so the sidebar ordering the reader encounters matches the package's actual role. what: - docs/packages/index.md: rename "Autodoc domain packages" to "Domain packages", add sphinx-autodoc-argparse to its bullet (alphabetically ordered), and rename the tier-3 bullet from "Theme, fonts, and CLI" to "Theme and coordinator" with argparse removed. - docs/architecture.md: add a sphinx-autodoc-argparse row to the Tier 2 table with its domain column noting the custom `argparse` domain and its ObjType vocabulary. Clarify the sphinx-autodoc-pytest-fixtures row as "extends `py` domain". Rename Tier 3 heading to "Theme and coordinator" and drop the argparse row. Update the closing sentence from "five domain packages" to "six".
… indices
why: The argparse domain is live (E1-E5) and sits in Tier 2 (E6),
but the package page has no user-facing documentation on how to
use the new xref roles or the two auto-generated indices. Add a
"Cross-reference roles" section covering the full role vocabulary,
the target-syntax rules (whitespace-joined vs bare), and the
intersphinx-compat contract — so readers know `:argparse:option:`
is now the idiomatic form without losing `:option:` access for
intersphinx consumers.
what:
- Add a "Cross-reference roles" section to
docs/packages/sphinx-autodoc-argparse.md after "Inline roles"
with:
* A four-row table listing :argparse:program: /
:argparse:option: / :argparse:subcommand: /
:argparse:positional: with concrete example targets.
* A short paragraph on target-syntax rules (whitespace-join
splits into a (program, name) tuple key; bare form resolves
when there's one match).
* "Auto-generated indices" subsection naming
argparse-programsindex and argparse-optionsindex with
:ref: link examples.
* "Intersphinx compatibility" note clarifying that
:option: / std:cmdoption continues to resolve and appear in
objects.inv for external consumers.
…Fonts/CLI to UX why: The Furo sidebar is driven by three hidden toctree blocks in docs/index.md, not by the narrative prose in docs/packages/index.md or docs/architecture.md. The previous E6 commit updated the narrative but not the sidebar, so readers still saw sphinx-autodoc-argparse listed under "Theme, Fonts & CLI" in every package page. Bring the sidebar in line with the architectural reclassification, and shorten the third-tier caption from "Theme, Fonts & CLI" to the cleaner "UX" now that argparse has moved out and only gp-sphinx / sphinx-gp-theme / sphinx-fonts remain. what: - docs/index.md: insert packages/sphinx-autodoc-argparse in the "Domain Packages" toctree between api-style and docutils (alphabetical order within the tier). - docs/index.md: rename the third toctree caption from "Theme, Fonts & CLI" to "UX"; remove packages/sphinx-autodoc-argparse from it. - Verified by clean-building docs and inspecting the rendered sidebar headings (Shared Infrastructure / Domain Packages / UX).
why: "Shared Infrastructure" bundled three heterogenous packages
under one caption — sphinx-ux-badges and sphinx-ux-autodoc-layout
are visual/styling primitives that naturally belong alongside
sphinx-fonts, while sphinx-autodoc-typehints-gp is a type-rendering
utility that doesn't fit either. The single generic caption made
it hard for a reader browsing the sidebar to reason about what each
package is for at a glance. Split into four purpose-named
captions so the navigation matches the conceptual categories.
what:
- docs/index.md: replace the three hidden toctrees (Shared
Infrastructure / Domain Packages / UX) with four captioned
toctrees:
* Domain Packages — the six autodoc-* extensions (unchanged).
* UX — sphinx-fonts, sphinx-ux-autodoc-layout, sphinx-ux-badges
(the three visual/styling primitives).
* Utils — sphinx-autodoc-typehints-gp (type-rendering utility
that replaces sphinx-autodoc-typehints + sphinx.ext.napoleon).
* Internal — gp-sphinx (metapackage / coordinator) and
sphinx-gp-theme (furo sub-theme), the two packages readers
don't install on their own.
- Alphabetise entries within each toctree for predictability.
- No narrative (docs/architecture.md, docs/packages/index.md)
changes in this commit; the architecture tiers describe
dependency layers and remain three-tier, while the sidebar
captions describe navigation buckets.
why: The README's "what you get" bullets advertised five domain autodocumenters and listed their targets (Python API, pytest fixtures, FastMCP tools, docutils directives, Sphinx config values) — missing argparse CLIs, which is now a sixth domain package with its own Sphinx Domain subclass and :argparse:* xref roles. Keeping the README aligned with the shipped reality prevents a reader from skipping sphinx-autodoc-argparse when they scan the bullet list to decide what the workspace covers. what: - Change "Five domain autodocumenters" -> "Six" on line 53 of README.md and insert "argparse CLIs" between "Python API" and "pytest fixtures" in the accompanying list. - No other README change; the three-tier architecture heading below stays — sidebar navigation (Domain / UX / Utils / Internal) and dependency tiers (three) describe different axes.
why: The What's New page counted seven advancements and the
"Shared layout stack" section listed five domain packages. The
argparse domain that landed in the recent seven-commit series (a
real Sphinx Domain subclass with :argparse:* roles and two
auto-generated indices) is a peer advancement that the page did
not yet describe. Update the counts and introduce the new section
so readers arriving via the sidebar's "What's new" card see the
whole picture.
what:
- Opening line: "seven major advancements" -> "eight".
- "Shared layout stack" section: "The five domain packages" -> "The
six domain packages"; add argparse to the {doc} list,
alphabetically between api-style and docutils.
- Insert a new "## argparse Sphinx domain" section between
"Shared layout stack" and "Three-tier package organization".
Describes the Domain subclass, the four :argparse:* xref roles,
the two auto-generated indices (argparse-programsindex,
argparse-optionsindex), and the intersphinx compatibility
contract with :option: / std:cmdoption.
why: The 0.0.1 (unreleased) Features section documented the two new foundation packages (sphinx-ux-autodoc-layout, sphinx-autodoc-typehints-gp) and the three-tier restructuring, but not the argparse Sphinx domain added in the recent E1-E7 commit series. Without a changelog entry, downstream alpha-testers reading CHANGES wouldn't know about the new :argparse:* xref roles or the two auto-generated indices. what: - Append one bullet to the ### Features section of the 0.0.1 (unreleased) entry describing the domain: ObjTypes, xref roles, indices, the new classifier, and the std:cmdoption compatibility guarantee.
why: The sidebar now uses four navigation buckets (Domain Packages, UX, Utils, Internal) while the architecture page continues to describe dependency layers in three tiers. A reader looking at both could reasonably wonder whether the discrepancy is a bug. Call out the two-axis framing explicitly so the choice reads as intentional: sidebar = reader-facing grouping; tier map = dependency ordering. what: - Append one sentence after the opening paragraph of docs/architecture.md clarifying that the four sidebar buckets are orthogonal to the three dependency tiers documented below. - No other content change; the three-tier structure stays as-is.
a11867c to
693130e
Compare
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.
Summary
gp-sphinxmoves from a shared-config package to an integrated autodoc design system. Twelve packages now sit in three clear tiers with one badge palette, one layout pipeline, one typehint renderer, and one CSS vocabulary — so Python APIs,argparseCLIs, pytest fixtures, Sphinx config values, docutils directives, and FastMCP tools all render like they belong together.sphinx-ux-autodoc-layout(card regions, parameter folding, managed signatures) andsphinx-autodoc-typehints-gp(single-package replacement forsphinx-autodoc-typehints+sphinx.ext.napoleon, resolves annotations statically at build time with no monkey-patching).sphinx-ux-badges,sphinx-ux-autodoc-layout,sphinx-autodoc-typehints-gp) at the bottom; six domain packages (-api-style,-argparse,-docutils,-fastmcp,-pytest-fixtures,-sphinx) in the middle; theme and coordinator (gp-sphinx,sphinx-gp-theme,sphinx-fonts) on top. Lower layers never depend on higher ones. The sidebar further splits into four reader-facing navigation buckets (Domain Packages, UX, Utils, Internal) — an orthogonal view of the same twelve packages.argparseSphinx domain —sphinx-autodoc-argparsenow ships a realDomainsubclass withprogram/option/subcommand/positionalObjTypes,:argparse:*xref roles, and two auto-generated indices (argparse-programsindex,argparse-optionsindex).:option:/std:cmdoptionkeeps emitting for intersphinx compat;Framework :: Sphinx :: Domainclassifier added.gp-sphinx-*two-tier BEM root (gp-sphinx-badge,gp-sphinx-fastmcp__*, etc.). The opaque per-package prefixes (sab-,smf-,spf-,api-,gas-,gal-) are gone, along with the duplicate palettes that hid behind them.env.domains.<name>_domaintyped accessors; eightt.cast/# type: ignoreworkarounds retired as a result.SphinxScenariocache keyed by content-hash SHA-256 reuses identical builds across tests (full-suite runtime ~40 s → ~4.2 s for 916 tests per the workspace's own profiling note). Most tests now run against the docutils doctree directly; a syrupy-based snapshot layer locks in doctree structure, rendered HTML, and warning output with path + ANSI normalization built in.Breaking changes (renames)
All old names redirect via
docs/redirects.txt, but imports need updating downstream:sphinx-argparse-neo→sphinx-autodoc-argparsesphinx-gptheme→sphinx-gp-themesphinx-autodoc-badges→sphinx-ux-badgessphinx-autodoc-layout→sphinx-ux-autodoc-layoutsphinx-typehints-gp→sphinx-autodoc-typehints-gpautosphinxconfig-indexdirective →autoconfigvalue-indexfastmcp-toolsummarydirective →fastmcp-tool-summarydoc-pytest-plugindirective →auto-pytest-pluginTest plan
Every commit on this branch passed the same gate before landing:
uv run ruff check . --fix --show-fixesuv run ruff format .uv run mypyuv run py.test --reruns 0 -vvv— 1123 passed / 3 skippedjust build-docsWorth eyes on from a reviewer:
docs/gallery.md) renders every badge variant and every autodoc component against the new CSS; confirm no visual regressions vs. the pre-branch build.sphinx-autodoc-api-styleloaded (the muting rule is now self-contained insphinx-autodoc-pytest-fixtures' own CSS as well).pytest -m integrationandpytest -m "not integration"both partition cleanly — every Sphinx-build test is marked.sphinx-autodoc-fastmcp,sphinx-autodoc-typehints-gp,sphinx-ux-badges,sphinx-ux-autodoc-layout).docs/architecture.mdanddocs/whats-new.mdaccurately describe the shipped state of the tier boundaries.