Skip to content

Normalize emitted asset paths for nested Sphinx pages#20

Merged
chrizzFTD merged 3 commits into
cursor/autodoc-bootstrap-src-only-16b5from
cursor/normalize-static-paths-1b91
Jul 2, 2026
Merged

Normalize emitted asset paths for nested Sphinx pages#20
chrizzFTD merged 3 commits into
cursor/autodoc-bootstrap-src-only-16b5from
cursor/normalize-static-paths-1b91

Conversation

@chrizzFTD

Copy link
Copy Markdown
Owner

Summary

Fixes #19 by rewriting file-like paths in emitted <py-repl> attributes to page-relative URLs at build time, so REPLs work on nested Sphinx pages (e.g. api/module.html) without breaking RTD-style path prefixes.

This deliberately uses Sphinx's get_target_uri() + relative_uri() rather than the issue's proposed /_static/… root-absolute paths, which would break docs hosted under version/language prefixes.

Changes

  • Add asset_href() / asset_href_packages() helpers in sphinx_pyrepl_web/__init__.py
  • Apply normalization when emitting packages, src, and replay-src in PyRepl.run() and make_pyrepl_raw()
  • Leave register_autodoc_*() return values unchanged (canonical paths for copy_asset_files())
  • Normalize all file-like paths (paths with /, or ending in .whl / .py); PyPI names, absolute URLs, and micropip specs are untouched
  • Add unit tests (tests/test_asset_href.py) and a nested-page HTML build test (tests/test_nested_static_paths.py)
  • Document automatic path rewriting in README

Behavior

Page Before After
index.html _static/wheels/foo.whl _static/wheels/foo.whl (unchanged)
api/index.html _static/wheels/foo.whl ../_static/wheels/foo.whl

Test plan

  • pytest tests/ — 41 passed
  • Unit tests for flat/nested paths, PyPI names, absolute URLs, comma-separated packages
  • Full HTML build on api/index.rst asserts page-relative paths in output
  • Existing flat-layout tests unchanged (regression)
Open in Web Open in Cursor 

Rewrite file-like paths in py-repl attributes to page-relative URLs
using Sphinx get_target_uri and relative_uri. This fixes REPL asset
loading on nested doc pages while preserving flat-layout behavior and
compatibility with RTD-style path prefixes.

Adds asset_href helpers, unit tests, a nested-page build fixture, and
README documentation. Closes #19.

Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
@read-the-docs-community

read-the-docs-community Bot commented Jul 2, 2026

Copy link
Copy Markdown

Documentation build overview

📚 sphinx-pyrepl-web | 🛠️ Build #33410103 | 📁 Comparing fa4eb00 against latest (931ed8b)

  🔍 Preview build  

3 files changed
± example.html
± genindex.html
± index.html

Use app.builder in transforms and env._app.builder in PyRepl.run(),
matching Sphinx internals. asset_href now takes a Builder directly.

Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
@chrizzFTD

Copy link
Copy Markdown
Owner Author

@cursoragent review

@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR Review: #20 — Normalize emitted asset paths for nested Sphinx pages

Verdict: Approve. This is a solid, well-scoped fix for #19. CI is green (latest run succeeded after the env.app deprecation fix), and the design is better than the issue’s original /_static/… proposal.


What works well

1. Correct path strategy

Using builder.get_target_uri(docname) + relative_uri() is the right Sphinx-native approach. It fixes nested pages and stays compatible with RTD/GitHub Pages prefix hosting — something root-absolute /_static/… would break.

2. Clean separation of concerns

  • register_autodoc_*() keeps canonical _static/pyrepl/… paths for copy_asset_files()
  • Normalization happens only at HTML emission sites (PyRepl.run(), make_pyrepl_raw())

That keeps metadata/copy logic simple and avoids double-rewriting.

3. Sensible file-like heuristic

def asset_href(builder: Builder, docname: str, path: str) -> str:
    """Rewrite a file path for the HTML page that will emit it."""
    if not _is_file_like_path(path):
        return path
    if builder.format != "html":
        return path
    return relative_uri(builder.get_target_uri(docname), path)

PyPI names, absolute URLs, micropip specs (pkg @ https://…), and non-HTML builders are all handled correctly. The .py extension handling covers :src: demo.py on nested pages.

4. Good test coverage

  • Unit tests for the helper (test_asset_href.py)
  • Integration test on a real nested build (api/index.html../_static/…)
  • Existing flat-layout tests unchanged (regression-safe)
  • CI’s PYTHONWARNINGS=error passes after switching to env._app.builder

5. CI fix is appropriate

env._app.builder matches what Sphinx’s own transforms use and avoids the RemovedInSphinx11Warning that CI treats as fatal.


Minor nits (non-blocking)

Item Note
env._app is private Acceptable — Sphinx internals use it too. When Sphinx 11 removes env.app, this should still work. Worth a one-line comment if you want future readers to know it’s intentional.
No autodoc-on-nested-page test make_pyrepl_raw() path (autodoc doctests + pyrepl_autodoc_packages) isn’t covered on a nested page. The directive path is tested; autodoc would follow the same code path, so low risk.
:src: RST resolution vs URL emission Separate pre-existing behavior: :src: _static/bootstrap.py in api/index.rst resolves relative to the RST file, not srcdir. URL rewriting can’t fix that. Not introduced by this PR, but worth knowing for nested-doc authors.
Public asset_href export Exported at package level (used in tests). Fine, but it’s effectively internal API unless documented.

RTD preview

The Read the Docs preview shows changes to index.html, example.html, genindex.html. This project’s docs are flat (index.rst, example.rst), so emitted paths on those pages should be unchanged (_static/… with no ../). Any HTML diffs are likely from Sphinx/theme/build drift, not a regression from this change.


Issue #19 acceptance criteria

Criterion Status
Normalization applied to all emitted file-like paths
Nested page HTML test
README note
Flat-layout consumers unaffected

Recommendation

Merge when ready. No required changes. Optional follow-ups (can be separate PRs):

  1. Add one autodoc doctest test on api/module.rst with pyrepl_autodoc_packages configured
  2. Note in README that :src: paths in RST are resolved relative to the containing .rst file (orthogonal to this URL rewrite)

Good work on pushing back against the /_static/… approach — that would have been a subtle RTD regression.

Open in Web Open in Cursor 

Rename asset_href and asset_href_packages to _asset_href and
_asset_href_packages so they are not mistaken for public extension API.

Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
@chrizzFTD
chrizzFTD merged commit 5444564 into cursor/autodoc-bootstrap-src-only-16b5 Jul 2, 2026
4 checks passed
@chrizzFTD
chrizzFTD deleted the cursor/normalize-static-paths-1b91 branch July 2, 2026 11:54
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.

2 participants