Skip to content

docs: Complete documentation site, add autodoc extensions, and MystLexer#7

Merged
tony merged 57 commits into
mainfrom
docs-updates
Apr 5, 2026
Merged

docs: Complete documentation site, add autodoc extensions, and MystLexer#7
tony merged 57 commits into
mainfrom
docs-updates

Conversation

@tony
Copy link
Copy Markdown
Member

@tony tony commented Apr 4, 2026

Summary

Large docs-and-feature branch covering three areas:

1. Documentation site build-out (62b65500e96e0b)

  • Complete package reference pages for all 7 packages (gp-sphinx, sphinx-fonts, sphinx-gptheme, sphinx-argparse-neo, sphinx-autodoc-docutils, sphinx-autodoc-sphinx, sphinx-autodoc-pytest-fixtures)
  • New docs/_ext/package_reference.py extension — introspects live setup() calls and renders directives, roles, and config-value tables automatically
  • docs/configuration.md — full reference for all merge_sphinx_config() defaults
  • docs/api.md — API reference with make_linkcode_resolve wiring example
  • docs/quickstart.md — "Your first build" tutorial section
  • Redirect map (docs/redirects.txt) for moved pages
  • Live demos on package pages using sphinx-autodoc-docutils and sphinx-autodoc-sphinx

2. New packages: sphinx-autodoc-docutils and sphinx-autodoc-sphinx

  • sphinx-autodoc-docutils — documents docutils directives and roles from Python callables as rst:directive/rst:role reference blocks
  • sphinx-autodoc-sphinx — documents Sphinx config values registered by app.add_config_value() as live confval entries and summary index tables
  • Both packages: full pyproject.toml, typed stubs (py.typed), NumPy docstrings, mypy-strict typing

3. MystLexer for {eval-rst} fenced block highlighting (968e4c337a3be0)

Root cause: MarkdownLexer's fenced-block language pattern [\w\-]+ rejects {eval-rst} (the {} don't match), so blocks fall through to plain Token.Text with no syntax spans.

  • packages/gp-sphinx/src/gp_sphinx/myst_lexer.pyMystLexer(MarkdownLexer) with a priority rule for ```{eval-rst} blocks; delegates body to RstLexer(handlecodeblocks=True) for 3-level nesting (MyST → RST → inner language)
  • stubs/pygments/lexers/markup.pyi — local stub for MarkdownLexer/RstLexer (not in types-Pygments)
  • config.py registers "myst"/"myst-md" aliases via app.add_lexer()
  • Doc pages changed from ````md to ````mystmd fell through to Pygments' MarkdownLexer while myst hits Sphinx's lexer_classes["myst"] (verified via live HTML inspection showing highlight-myst class and proper <span class="sb"> elements)

Fixes

  • refactor(config): Add description= to all add_config_value() calls
  • fix(sphinx-fonts): Shorten description strings for E501
  • fix(docs): GitHub source links tree/mastertree/main
  • fix(sphinx-autodoc-sphinx): option_spec type annotation and _Opt tuple unpacking

Test plan

  • uv run pytest — 611 passed, 3 skipped
  • uv run mypy — no issues
  • uv run ruff check . — no issues
  • Visual: {eval-rst} blocks on /packages/sphinx-autodoc-sphinx/ and /packages/sphinx-autodoc-docutils/ render with highlight-myst class and RST syntax spans

tony added 30 commits April 3, 2026 19:05
…g reference, and API

why: The extensions/ hub had 3 dead-end cards (sphinx-fonts, sphinx-gptheme,
sphinx-argparse-neo linked to nothing), no configuration reference for
merge_sphinx_config(), and no API docs.
what:
- Rename extensions/ to packages/ (gp-sphinx and sphinx-gptheme aren't
  extensions; packages/ matches the UV workspace vocabulary)
- Add package pages for gp-sphinx, sphinx-fonts, sphinx-gptheme, and
  sphinx-argparse-neo with badges, install commands, usage examples,
  and source links
- Add configuration.md: full parameter table for merge_sphinx_config(),
  auto-computed values, hardcoded defaults, shared defaults by category
  (extensions, theme, fonts, MyST, autodoc, copybutton, napoleon)
- Add api.md: autodoc for merge_sphinx_config, make_linkcode_resolve,
  deep_merge
- Update landing page: add Packages and Configuration cards
- Add redirect entries for old extensions/ URLs
…e_neo.exemplar

why: argparse_exemplar is not importable as a top-level module — downstream
users copying the quickstart example get ModuleNotFoundError. The correct
Sphinx extension name is sphinx_argparse_neo.exemplar.
what:
- Fix docs/quickstart.md extra_extensions example
- Fix config.py docstring example
… warning

why: autodoc interprets **overrides as malformed bold RST markup when
rendering api.md, producing parse warnings under -W.
what:
- Escape as \**overrides in the parameter list and prose
- Use raw docstring (r""") to support the backslash escapes
…ge demo

why: The page was a badge gallery with no install, config, directive, or
role documentation. All 4 config values, 4 directives, 1 role, and 11
py:fixture options were undocumented.
what:
- Add maturity badge, install commands, usage example
- Document all 4 registered config values with defaults
- Document all directives (py:fixture, autofixture, autofixtures,
  autofixture-index) and the :fixture: role
- Document all py:fixture directive options
- Add source link
- Badge demo section preserved below reference content
…ons, lexers, and roles

why: The page documented 0/4 base config values, 0/9 exemplar config
values, 0/7 directive options, 0/4 lexers, and 0/5 CLI roles.
what:
- Document 4 base config values with defaults
- Document key argparse directive options
- Add exemplar sub-extension section with correct extension name
  (sphinx_argparse_neo.exemplar, not argparse_exemplar)
- Document 9 exemplar config values, 4 Pygments lexers, 5 CLI roles
- Clarify lexers and roles are registered by the exemplar, not the base
why: The page listed bundled files but documented 0/7 theme.conf options,
no copyable html_theme_options example, and no template/stylesheet detail.
what:
- Document all 7 theme.conf options with descriptions
- Add copyable html_theme_options example
- Document templates (brand, projects), stylesheets (custom, argparse),
  and JavaScript (spa-nav.js)
- Document theme inheritance and entry point
…xt variables

why: Config table documented names but omitted default values from
gp-sphinx and the template integration contract that downstream theme
authors need.
what:
- Add gp-sphinx default values for all 4 config options
- Document the FontConfig dict shape
- Document 4 template context variables injected during html-page-context
  (font_faces, font_preload_hrefs, font_fallbacks, font_css_variables)
…_options

why: The page summarized defaults by behavior but never named the actual
constants or their values — downstream authors couldn't verify coverage
against the source.
what:
- Add DEFAULT_AUTODOC_OPTIONS dict (5 keys)
- Add DEFAULT_SOURCE_SUFFIX, DEFAULT_HTML_STATIC_PATH, DEFAULT_TEMPLATES_PATH
- Add copybutton constant names and values
- Add napoleon and suppress_warnings constant names
why: README.md was 0 bytes — PyPI and editor-side DX showed no
package description.
what:
- Add description, install command, usage example, and docs link
why: The argparse demo used "gp-demo" with "build"/"serve" subcommands,
which didn't look like obvious examples. Epilog text also rendered as
unformatted paragraphs due to a nested_parse limitation.
what:
- Rewrite demo_cli.py with generic names (myapp, mysubcommand,
  myothersubcommand) and remove epilog that triggered rendering bug
- Fix RUF012 in docutils_demo.py: add ClassVar to option_spec
- Fix E501 in sphinx_config_demo.py, sphinx_config_single_demo.py:
  shorten doctest stub construction
…nx, and package-reference directive

why: Enable auto-generated reference tables for directives, roles, and
config values across all package docs pages, replacing static Markdown
tables with live introspection.
what:
- Add sphinx-autodoc-docutils package with autodirective, autorole,
  autodirective-index, autorole-index directives
- Add sphinx-autodoc-sphinx package with autoconfigvalue,
  autoconfigvalues, autoconfigvalue-index directives
- Add package_reference.py docs extension (auto-generates registered
  surface tables from setup() introspection)
- Rewrite all package docs pages to use live autodoc directives
- Add argparse_neo_demo.py with subcommand and epilog examples
- Register new extensions in conf.py with env-gated intersphinx
- Add workspace packages to pyproject.toml, ruff, and mypy config
- Add tests for autodoc-docutils, autodoc-sphinx, and package-reference
- Add CSS for package demo cards and font specimens
- Add redirects for new package doc pages
why: Base class Directive expects dict[str, Callable] | None, not
dict[str, object].
what:
- Change option_spec annotation from dict[str, object] to
  dict[str, t.Any] in AutoconfigvalueDirective and
  AutoconfigvaluesDirective
…with attribute access

why: Sphinx 8.x changed config values from 3-tuples to _Opt instances.
The t.cast + tuple unpacking emits 4 RemovedInSphinx90Warning per call
and will crash in Sphinx 9.
what:
- Use isinstance(opt, tuple) guard for backward compat with old Sphinx
- Access .default, .rebuild, .valid_types attributes on _Opt instances
- Remove unused import typing (cleaned by ruff)
…) functions

why: ExtensionMetadata is a public TypedDict from sphinx.util.typing
(Sphinx 7.3+) that catches typos in metadata keys at type-check time.
what:
- Add TYPE_CHECKING import of ExtensionMetadata in both packages
- Change setup() return annotation from dict[str, t.Any] to
  ExtensionMetadata
…rom sphinx.util.typing

why: OptionSpec (dict[str, Callable[[str], Any]]) is Sphinx's public
type alias for directive option specs, available since Sphinx 4.0.
what:
- Add TYPE_CHECKING import of OptionSpec in both packages
- Annotate all option_spec class attributes with ClassVar[OptionSpec]
- Add import typing as t to docutils _directives.py (was missing)
…nSpec | None

why: The parameter receives Directive.option_spec values which are
dict[str, Callable[[str], Any]] | None per types-docutils stubs.
what:
- Change _option_rows(option_spec: object) to OptionSpec | None
- isinstance guard on line 116 still narrows correctly for mypy
…ations

why: Both packages ship py.typed with strict mypy. Reviewers and
contributors need to know why object is used instead of Any or a
narrower type in 14+ locations.
what:
- Add brief inline comments on every intentional object annotation
  explaining why it is the correct type (e.g., wraps inspect.getdoc,
  config defaults are heterogeneous, roles have monkey-patched attrs)
- Comments follow pattern: # object: <reason>
… config extractor

why: _config_values_from_calls() required 3+ positional args, silently
dropping extensions that use keyword args (e.g., sphinx-autodoc-pytest-
fixtures passes default=, rebuild=, types= as kwargs).
what:
- Lower guard from len(args) < 3 to len(args) < 1
- Read default/rebuild/types/description from kwargs with positional
  fallback
- Add kwargs-style doctest to verify extraction
…face extractor

why: Same bug as sphinx-autodoc-sphinx — len(args) < 2 guard dropped
kwargs-style calls where default/rebuild are keyword arguments.
what:
- Lower guard from len(args) < 2 to len(args) < 1
- Read default from kwargs with positional fallback
why: The quickstart stopped at the conf.py snippet with no build
command, directory creation, or verification step. A new user could
not go from zero to rendered docs.
what:
- Add mkdir, index.md creation, sphinx-build command, and browser step
- Reference the Usage section for conf.py pattern
why: The install command used the old single-package form that doesn't
resolve workspace members.
what:
- Change uv sync --all-extras --dev to
  uv sync --all-packages --all-extras --group dev
…nd :exclude: options

why: The only filtering and sorting mechanisms for bulk fixture
documentation were invisible to users.
what:
- Add autofixtures option table (:order:, :exclude:)
- Add autofixture-index option table (:exclude:)
why: The autofunction block showed the signature but not how to wire
the resolver into merge_sphinx_config() via **overrides.
what:
- Add conf.py example showing linkcode_resolve= usage
- Note that sphinx.ext.linkcode is auto-appended to extensions
why: sphinx-fonts registers no directives or roles — only config values
and template context hooks. The empty heading was confusing.
what:
- Remove the "Directives and Roles" heading and its empty
  autodirective-index/autorole-index blocks
why: Pages demoed index + single-object directives but skipped bulk
variants (autodirectives, autoroles, autoconfigvalues) — the forms
most users reach for first.
what:
- Add autodirectives and autoroles bulk demos to sphinx-autodoc-docutils
- Add autoconfigvalues bulk demo to sphinx-autodoc-sphinx
- Pass :no-index: through to rst:directive:option:: to avoid duplicate
  description warnings in bulk rendering
why: Sphinx 8.2.3+ accepts description= as structured metadata for
config values. Enriches self-documentation and future autodoc rendering.
what:
- Add description= to all 21 add_config_value() calls across
  sphinx-fonts (4), argparse-neo base (4), argparse-neo exemplar (9),
  and sphinx-autodoc-pytest-fixtures (4)
- Fix sphinx-fonts test mocks to accept **kwargs
why: Repository default branch is main, not master; links 404 otherwise.
what:
- Update 7 docs/packages/*.md source links
- Update hardcoded fallback URL in docs/_ext/package_reference.py
…dule docstring

why: New contributors had no entry point for understanding how the
     auto-generation pipeline works or how to extend it.
what:
- Describe the three-layer pipeline (discovery, surface extraction, rendering)
- Explain how to add a new package (no code changes needed)
- Explain how to extend the surface extractor for new app.add_* calls
…dmonition

why: Missed in the batch master→main fix; the blob URL pointed to the
     wrong branch and would 404 for users following the link.
what:
- docs/packages/gp-sphinx.md: blob/master → blob/main for conf.py link
…r fence

why: Multiple eval-rst blocks inside a single quadruple-backtick fence
     render as a single copyable unit, making individual commands hard
     to copy independently.
what:
- Separate each code block into its own ````md ... ```` fence
- Affects both single-object examples (autodirective/autorole) and
  bulk-directive examples (autodirective-index/autodirectives/
  autorole-index/autoroles)
tony added 4 commits April 4, 2026 10:35
…k highlighting

why: MarkdownLexer's fenced-block language pattern [\w\-]+ rejects {eval-rst}
(the {} are not word chars), so blocks in .myst.md source files fall through
to plain Token.Text with no syntax spans when shown via literalinclude.
what:
- Add MystLexer(MarkdownLexer) with a priority rule for ```{eval-rst} blocks
- _handle_eval_rst() emits opening/closing fences as String.Backtick and
  delegates the body to RstLexer(handlecodeblocks=True) for 3-level nesting:
  MyST fence → RST directive → inner language (e.g. Python)
- Add tokenize_myst() convenience wrapper for tests and doctests
- Full NumPy docstrings with working doctests throughout
…t suite

why: MystLexer must be registered with Sphinx so ````myst fences in docs
select it via lexer_classes["myst"] in PygmentsBridge.get_lexer(); tests
document and lock the token output for all key cases.
what:
- Import MystLexer in config.py and register "myst"/"myst-md" aliases via
  app.add_lexer() in the setup() hook
- Add tests/ext/test_myst_lexer.py with NamedTuple+parametrize pattern:
  FenceFixture (opening/info-string/closing as String.Backtick),
  RegressionFixture (plain text and standard Python fences still work),
  NestedHighlightFixture (3-level RST→Python nesting, documents trailing-
  blank-line requirement from RstLexer._handle_sourcecode)
- Standalone tests: empty block, multiple blocks, EOF without newline,
  tokenize_myst helper
why: ````md triggers MarkdownLexer (via Pygments fallback get_lexer_by_name)
whose fenced-block rule uses [\w\-]+; {eval-rst} contains {} so it doesn't
match, and the block emits <span></span> + raw text (class="highlight-md").
````myst hits lexer_classes["myst"] in PygmentsBridge.get_lexer() at
sphinx/highlighting.py:160 before the Pygments fallback, selecting MystLexer.
what:
- sphinx-autodoc-docutils.md: 6 occurrences ````md → ````myst
- sphinx-autodoc-sphinx.md: 2 occurrences ````md → ````myst
- sphinx-argparse-neo.md: 1 occurrence ````md → ````myst
…s for E501

why: Three description= strings added in b209492 exceeded the 88-char
line limit enforced by ruff E501, blocking a clean ruff check run.
what:
- sphinx_fonts: "Font family dicts (family, package, version, weights, styles)."
- sphinx_font_fallbacks: "Fallback @font-face declarations with metric overrides for CLS."
- sphinx_font_preload: "Critical font variants to preload (family, weight, style)."
@tony tony marked this pull request as ready for review April 4, 2026 15:59
tony added 19 commits April 4, 2026 11:42
why: Bare next(generator) raised StopIteration and crashed the Sphinx
build for any package-reference directive with an unrecognised name.
what:
- Add default=None to next() and return "" with a logged warning
- Add import logging and module-level logger
- Add doctest and test_package_reference_markdown_unknown_package_returns_empty
… ImportError

why: All three import_module() call sites were unguarded; any missing
dependency or syntax error in a workspace package crashed the full build.
what:
- extension_modules(): wrap top-level import and submodule loop in try/except
- collect_extension_surface(): wrap import and return empty SurfaceDict on failure
- Log a warning at each site so the skipped module is visible in the build output
- Add test_extension_modules_skips_unimportable_module
- Add test_collect_extension_surface_skips_unimportable_module
…ainst empty markup

why: AutoDirectives.run() and AutoRoles.run() called _render_blocks(self, markup)
without a guard, unlike AutoDirectiveIndex which already has if markup else [].
Modules with no directive classes or role callables produced a markup="" call
that is inconsistent with the Index variant behaviour.
what:
- Add `if markup else []` guard to AutoDirectives.run() (line 332)
- Add `if markup else []` guard to AutoRoles.run() (line 392)
- Add test_directive_classes_empty_for_module_with_no_directives
- Add test_role_callables_empty_for_module_with_no_roles
why: CLAUDE.md requires all functions/methods to have working doctests;
setup() only had a one-line docstring with no doctest.
what:
- Add FakeApp doctest matching the pattern in sphinx_autodoc_sphinx/__init__.py
- Verify autodirective is registered and parallel_read_safe is True
…o library __init__ files

why: CLAUDE.md requires NullHandler in every library __init__.py; neither
new package had it, causing logging.lastResort to print WARNING+ to stderr
in user projects that don't configure logging.
what:
- Add import logging and NullHandler to sphinx_autodoc_docutils/__init__.py
- Add import logging and NullHandler to sphinx_autodoc_sphinx/__init__.py
…lel-build constraint

why: Two code review findings flagged undocumented constraints: _render_blocks()
is silently duplicated across both autodoc packages, and the docutils global
monkey-patch in collect_extension_surface() is not safe for parallel builds.
what:
- Add NOTE comment above both _render_blocks() copies explaining the duplication
  and why extraction requires a new dep (extract to gp_sphinx._render if a third
  caller emerges)
- Add comment in collect_extension_surface() explaining the try/finally pattern
  and noting the parallel-build limitation (sphinx -j N)
why: Badges after H1 had inverted visual gravity — more whitespace above
than below — making them read as floating unattached metadata rather than
a subtitle. sphinx-design defaults use Bootstrap-era bright solid fills
that clash with the Furo muted aesthetic.

what:
- Tighten h1 bottom margin (0.75rem → 0.2rem) so the badge strip reads
  as attached subtitle via `article > section > h1`
- Convert badge-only first-<p> into a flex metadata strip using CSS :has()
- Reset .sd-badge to inline-flex, compact sizing, lower border-radius
- Add --badge-alpha-* / --badge-beta-* CSS vars for Furo dark mode:
  body[data-theme="dark"] for explicit mode,
  @media (prefers-color-scheme: dark) { body:not([data-theme="light"]) }
  for auto mode (two separate blocks — cannot combine as selector list)
- Alpha: sd-outline-warning → warm amber outline with color-mix tint
- Beta: sd-outline-success → cool green outline with color-mix tint
- Type badges (sd-bg-primary/success/info): muted gray, scoped to
  metadata strip paragraph only
- .sd-card-footer .sd-badge: compact sizing for grid index cards
…ard footer

why: maturity_badge() was injected directly into the grid-item-card title
f-string, making it impossible to reposition via CSS. Moving it to the +++ footer
section lets the .sd-card-footer CSS rule style it independently.

what:
- workspace_package_grid_markdown(): remove maturity_badge() from card title,
  add blank line + +++ + maturity_badge() before ::: close
- Add "+++" doctest assertion to verify footer section presence
- tests/test_package_reference.py: add MaturityBadgeFixture NamedTuple parametrize
  for maturity_badge() inputs; GridMarkdownFixture parametrize for structural
  checks; separate test asserting no badge appears in card title lines
…ages

why: Type (extension/theme/coordinator) is redundant on individual package
pages — the URL, breadcrumb, and section heading already communicate where
you are. The maturity signal (Alpha/Beta) is the one piece of metadata that
earns page-level real estate. Type badge survives in the grid index cards.

what:
- Remove {bdg-primary}`extension`, {bdg-success}`coordinator`, {bdg-info}`theme`
  from line 3 of all 7 docs/packages/*.md files
- Keep maturity badge ({bdg-warning-line}`Alpha` / {bdg-success-line}`Beta`) only
…nt overrides

why: Previous color-mix approach was doubly broken — sphinx-design sets
color and border-color with !important on .sd-text-warning/.sd-outline-warning,
silently discarding our overrides; and color-mix(20%, transparent) resolved
to a near-invisible tint on Furo's off-white card footer background.

what:
- Replace color-mix backgrounds with opaque Radix amber-3/green-3 hex values
- Add !important to color and border-color to match sphinx-design's own escalation
- Switch to background-color (narrower override; no !important needed)
- Use Radix step-12 text (11.62:1/10.55:1 AAA), step-11 border (WCAG 1.4.11 ✓)
- Add --badge-alpha-bg / --badge-beta-bg variables for clean dark-mode override
- Dark mode: Radix amber-3/green-3 dark tints with step-11 text (9.13:1/6.66:1)
…ygments code blocks

why: Dict/frozenset defaults (e.g. pytest_fixture_builtin_links with 6 full
URLs) rendered as huge single-line <code> elements inside confval entries,
breaking layout. Direct node construction bypasses RST re-parsing and build
cache issues.
what:
- Add _COMPLEX_REPR_THRESHOLD (60 chars) and _is_complex_default() helper
- Add _make_default_block() returning nodes.literal_block with language=python
- Add _iter_desc_content() to traverse desc_content nodes from parsed output
- Omit :default: field in render_config_value_markup() for complex values
- Inject literal_block directly into desc_content in AutoconfigvaluesDirective
- Add parametrized test_is_complex_default, test_make_default_block, and
  test_render_config_value_markup_omits_default_for_complex
…rt name

why: Full dotted paths like sphinx_autodoc_docutils._directives.AutoDirectives
made the Callable column very wide; linking to the autodoc entry and showing
only the short name is more scannable and navigable.
what:
- Change object_path() to return {py:obj}`~module.Name` cross-reference markup
- Update hard-coded add_crossref_type callable to {py:meth}`~...` form
- Update object_path() doctest to reflect new return format
…erences

why: The Callable column showed full dotted paths as plain code. With py:obj
roles resolved to the py domain, they now render as clickable short names.

what:
- Add _register_extension_objects() to populate py domain from workspace
  extension setup() calls on env-check-consistency (after all docs are read
  but before the write phase resolves xrefs)
- Use env-check-consistency not env-before-read-docs: clear_doc() wipes
  domain entries whose docname matches the page being re-read, making
  pre-registration in env-before-read-docs invisible to the resolver
- Add parametrized test_register_extension_objects_populates_py_domain
  covering directives and role classes for multiple packages
- Update object_path() docstring and doctest to reflect {py:obj} markup
why: _register_extension_objects() only ran setup() on the base module,
missing roles/lexers/directives from submodules like sphinx_argparse_neo.exemplar.
Also missed docutils roles registered via register_local_role() rather than
app.add_role() (e.g. cli_option_role in sphinx_argparse_neo.exemplar).
what:
- Loop over extension_modules() (all submodules with setup()) not just base module
- Patch docutils register_local_role/register_canonical_role during setup() to
  capture docutils-registered roles alongside app.add_role() calls
- Add exemplar_role_from_submodule fixture to domain registration tests
…o fix B023

why: _capture was defined inside a for-loop body and closed over docutils_roles
without binding it, creating a latent late-binding closure bug (ruff B023).
Also fix RUF012 on _MockPyDomain/_MockEnv mock classes in the test.
what:
- Add _roles: list[tuple[str, object]] = docutils_roles default arg to _capture
- Annotate mock class attributes with t.ClassVar in test_package_reference.py
…ences

why: Inline mentions of merge_sphinx_config(), setup(), etc. were unlinked
plain code; MyST {py:func} roles make them navigable cross-references.
what:
- Add autofunction entry for gp_sphinx.config.setup to api.md
- Link gp_sphinx.config.merge_sphinx_config in configuration.md, index.md,
  packages/gp-sphinx.md, packages/sphinx-gptheme.md, and api.md prose
- Link gp_sphinx.config.setup in configuration.md (intro paragraph + table)
…phinx

why: intersphinx_mapping was gated behind GP_SPHINX_ENABLE_INTERSPHINX=1
with no real benefit — Sphinx caches objects.inv locally after first fetch,
and CI already has network access. Remove the gate and always map both targets.
what:
- Remove os import and env-var conditional
- Always enable py (docs.python.org) and sphinx (sphinx-doc.org) mappings
- Use /3/ suffix on Python URL for stable version
why: Now that intersphinx is always enabled we can cross-reference Sphinx's
own API docs from prose that mentions those symbols.
what:
- sphinx-autodoc-sphinx.md: link add_config_value via {py:meth}sphinx:~...
- configuration.md: link sphinx.ext.linkcode via {py:mod}sphinx:...
- packages/gp-sphinx.md: link sphinx.ext.linkcode
- api.md: link sphinx.ext.linkcode in make_linkcode_resolve prose
@tony
Copy link
Copy Markdown
Member Author

tony commented Apr 5, 2026

Code review

Found 3 issues:

  1. config.py docstrings for deep_merge, make_linkcode_resolve, and merge_sphinx_config use Sphinx :param:/:type:/:rtype: style instead of NumPy Parameters\n---------- / Returns\n------- style. (CLAUDE.md says "Follow NumPy docstring style for all functions and methods")

:param base: The base dictionary.
:type base: dict
:param override: The dictionary whose values take precedence.
:type override: dict
:returns: A new merged dictionary.
:rtype: dict

  1. packages/sphinx-autodoc-sphinx/src is absent from testpaths in pyproject.toml, so the 20 doctests in sphinx_autodoc_sphinx/_directives.py are never collected by the default test run. (CLAUDE.md says "Doctests MUST actually execute")

gp-sphinx/pyproject.toml

Lines 158 to 167 in 9eaec87

]
testpaths = [
"tests",
"docs",
"packages/gp-sphinx/src",
"packages/sphinx-fonts/src",
"packages/sphinx-gptheme/src",
]
filterwarnings = [
"ignore:distutils Version classes are deprecated. Use packaging.version instead.",

  1. docs/conf.py passes source_branch="master" to merge_sphinx_config(), which populates html_theme_options["source_branch"]. Sphinx-gptheme uses this to build the "View source" and "Edit on GitHub" links on every docs page. The repo's default branch is main, so those links 404. The PR's own master→main sweep (64914ad, abe27e5) fixed prose URLs but missed this parameter.

gp-sphinx/docs/conf.py

Lines 34 to 38 in 9eaec87

source_repository=f"{gp_sphinx.__github__}/",
docs_url=gp_sphinx.__docs__,
source_branch="master",
extra_extensions=[
"package_reference",

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

tony added 3 commits April 4, 2026 19:53
why: CLAUDE.md mandates NumPy docstring style; deep_merge, make_linkcode_resolve,
and merge_sphinx_config used Sphinx :param:/:type:/:rtype: format instead.
what:
- Convert deep_merge docstring to NumPy Parameters/Returns sections
- Convert make_linkcode_resolve docstring to NumPy Parameters/Returns sections
- Convert merge_sphinx_config docstring to NumPy Parameters/Returns sections
why: 21 doctests in sphinx_autodoc_sphinx/_directives.py were never collected
because packages/sphinx-autodoc-sphinx/src was absent from testpaths.
what:
- Add packages/sphinx-autodoc-sphinx/src to pytest testpaths in pyproject.toml
…" to "main"

why: Repo default branch is main; "master" default caused broken "Edit on GitHub"
and "View source" links on every docs page.
what:
- Change source_branch parameter default in merge_sphinx_config() to "main"
- Change DEFAULT_THEME_OPTIONS["source_branch"] seed value to "main"
- Update docs/conf.py source_branch kwarg to "main"
- Update configuration.md table rows to reflect new defaults
@tony tony merged commit a053449 into main Apr 5, 2026
6 of 16 checks passed
@tony tony deleted the docs-updates branch April 5, 2026 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant