Skip to content

Local wheels, config-driven autodoc REPLs, and pyrepl-web re-vendor#16

Merged
chrizzFTD merged 16 commits into
mainfrom
cursor/autodoc-bootstrap-src-only-16b5
Jul 5, 2026
Merged

Local wheels, config-driven autodoc REPLs, and pyrepl-web re-vendor#16
chrizzFTD merged 16 commits into
mainfrom
cursor/autodoc-bootstrap-src-only-16b5

Conversation

@chrizzFTD

@chrizzFTD chrizzFTD commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

Delivers branch-aware autodoc doctest REPLs via local Pyodide wheels, replacing module introspection with explicit configuration. Stacks Phase 0 (#14) with follow-on work from #17, #18, #20, and #21.

Release: 0.3.0

Changes

pyrepl-web vendor

  • Re-vendored from pyrepl-web PR #5 (cursor/resolve-package-urls-0bbd@1d95c619)
  • Includes interactive replay mode (replay-src) and relative wheel URL resolution for micropip.install()

Phase 0 — local Pyodide wheels (#14)

  • Wheel fixture + local wheel tests (directive passthrough, static copy, packages+src+replay, mixed PyPI+wheel)
  • README/docs for local wheel workflow; html_static_path = ["_static"] in docs/conf.py
  • scripts/build_test_pkg_wheel.py to rebuild/copy the committed fixture wheel

Autodoc REPL configuration (#17)

  • Remove pyrepl_autodoc_bootstrap and module introspection (importlib / inspect)
  • Add pyrepl_autodoc_packages — single config knob for autodoc package preload (wheel path or PyPI name)
  • Consolidate demo around pyrepl_test_pkg; [docs] extra installs the fixture for pip install -e ".[docs]"

Auto-import bootstrap (#18)

  • When pyrepl_autodoc_packages is set, generate a silent src= bootstrap script from autodoc metadata
  • Bootstrap scripts written to _static/pyrepl/{docname}-{n}-bootstrap.py

Nested page paths (#20)

  • Rewrite _static/... paths to page-relative URLs via Sphinx relative_uri (e.g. ../_static/wheels/foo.whl on nested pages)

Test suite (#21)

  • Layered unit/ / doctree/ / integration/ tests with shared fixtures

Autodoc behavior

pyrepl_autodoc_packages Browser REPL
unset / None / "" Replay doctest input only
wheel path or PyPI name packages= install → silent import bootstrap → interactive replay

Breaking changes (0.2.0 → 0.3.0)

  • pyrepl_autodoc_bootstrap removed (use pyrepl_autodoc_packages instead)
  • :silent: directive option removed

Test plan

  • pytest — 46 passed
  • sphinx-build docs — passed
  • python -m build + twine check dist/* — passed
  • Manual: autodoc REPL on docs example page loads pyrepl_test_pkg from wheel and runs doctest replay
Open in Web Open in Cursor 

Stop falling back to packages= for installed modules in
_resolve_autodoc_bootstrap. In-tree modules still get silent :src:
bootstrap; out-of-tree modules replay doctest input only until explicit
wheel paths are configured in a follow-up.

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

read-the-docs-community Bot commented Jun 30, 2026

Copy link
Copy Markdown

Documentation build overview

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

  🔍 Preview build  

4 files changed
+ development.html
± genindex.html
± index.html
- example.html

cursoragent and others added 2 commits June 30, 2026 21:57
- Add wheel fixture and tests/test_local_wheel.py (doctree, full build,
  packages+src+replay, comma-separated packages)
- Document local Pyodide wheel workflow in README and docs/example.rst
- Set html_static_path in docs/conf.py so wheels are copied to output
- Re-vendor pyrepl-web from cursor/resolve-package-urls-0bbd (PR #5) for
  runtime relative wheel URL resolution

Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
Vendor cursor/resolve-package-urls-0bbd@1d95c619, which is rebased onto
grill with replay mode (#4) and relative wheel URL resolution. Restores
replay-src runtime support that was lost in the earlier pre-rebase vendor.

Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
* Config-driven autodoc packages via wheel path

Replace module introspection and silent :src: bootstrap for autodoc REPLs
with a single pyrepl_autodoc_packages config value. Remove
pyrepl_autodoc_bootstrap.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
@cursor cursor Bot changed the title Limit autodoc bootstrap to in-tree :src: only Local wheels, config-driven autodoc REPLs, and pyrepl-web re-vendor Jul 2, 2026
@chrizzFTD

Copy link
Copy Markdown
Owner Author

@cursoragent review

@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR Review: #16 — Local wheels, config-driven autodoc REPLs, and pyrepl-web re-vendor

Verdict: Approve. This is a solid, cohesive delivery of Phase 0 plus the planned autodoc wheel workflow. RTD preview built successfully; 31 tests pass locally.


What works well

Architecture. Replacing module introspection with pyrepl_autodoc_packages is the right call. One explicit config knob covers wheel preload, and the auto-import bootstrap (#18) makes it actually usable with standard unqualified doctest names — without modifying docstrings.

Clean separation of concerns.

Layer Mechanism
Package install packages= from config
Namespace setup Silent src= bootstrap (generated imports)
Interactive UX replay-src= (original doctest input)

Extension code is lean. importlib/inspect are gone; autodoc_bootstrap_source() is small, pure, and well unit-tested. Bootstrap gating (packages must be set) is correct — imports without an installed package would be pointless.

Test coverage is strong for the behaviors that matter:

  • Wheel passthrough + static copy (test_local_wheel.py)
  • Autodoc with packages: wheel, bootstrap src=, replay content (test_autodoc_packages_emits_configured_wheel)
  • Out-of-tree modules get same config-driven behavior (test_autodoc_packages_for_out_of_tree_module)
  • Unset config → replay-only (test_autodoc_without_packages_is_replay_only)
  • Import derivation units (test_autodoc_bootstrap_source.py)

Vendored JS is correct. pyrepl.esm.js includes both replaySrc handling and resolvePackageRefs for wheel URLs — the regression from the earlier pre-rebase vendor is fixed.

Docs/tooling. README, docs/example.rst, docs/conf.py, build_test_pkg_wheel.py, and the [docs] extra tell a coherent end-to-end story. The RTD preview confirms the docs build.


Issues / nits (non-blocking)

1. Upstream dependency: pyrepl-web PR #5 still open

Assets are vendored from cursor/resolve-package-urls-0bbd@1d95c619, not merged grill. Fine for this stacked PR, but merge pyrepl-web #5 before or with this so the vendor SHA matches a stable upstream ref. Note in release notes.

2. Wheel must match the documented package

test_autodoc_packages_for_out_of_tree_module documents installed_pkg.Widget but installs the pyrepl_test_pkg wheel — bootstrap correctly generates from installed_pkg import Widget, but runtime would fail. That's acceptable for a build-time test; worth a one-line README note that the configured wheel must contain the documented package.

3. Known bootstrap limitations (document, don't block)

Scenario Bootstrap May still fail at replay
Nested inner class (Outer.Inner) from mod import Outer bare Inner()
Instance methods using self imports class only needs instance in doctest
Multi-package projects single pyrepl_autodoc_packages value one wheel/name assumed

These are inherent limits of metadata-only import guessing, not regressions.

4. Nested page paths not normalized

_static/wheels/foo.whl works for flat layouts (index.html) but breaks on nested pages (api/module.html) until root-absolute paths (/_static/...) are emitted. Already tracked as follow-up; fine to ship for flat-layout consumers (naming, costa).

5. literalinclude crosses repo boundaries

.. literalinclude:: ../../tests/fixtures/pyrepl_test_pkg/pyrepl_test_pkg/demo.py

Works on RTD; slightly unusual for published docs. Acceptable for a maintainer-facing example site.

6. [docs] extra not installable from PyPI

Path dependency in pyproject.toml — clone-only. Already documented.

7. Bootstrap files written inside replay loop

        raw_bootstrap = metadata.get(BOOTSTRAP_FILES_KEY)
        if raw_bootstrap:
            bootstrap_files = json.loads(raw_bootstrap)
            for name, content in bootstrap_files.items():
                (replay_dest / name).write_text(content, encoding="utf-8")

Bootstrap copy only runs when replay files exist for that docname. Always true today since they're registered together, but a separate loop would be more robust. Low priority.

8. Minor test gaps

  • No test for pyrepl_doctest_blocks = "all" with packages set (confirm plain RST doctests skip bootstrap)
  • No test for comma-separated pyrepl_autodoc_packages on the autodoc path (covered for manual directive in test_local_wheel.py)

Breaking change (document on merge to main)

pyrepl_autodoc_bootstrap removed with no deprecation shim. Appropriate pre-1.0; call out in merge/release notes.


Merge checklist

Step Status
pytest (31 passed)
RTD preview build
pyrepl-web #5 merged (or vendor SHA updated) pending upstream
Manual: autodoc REPL loads wheel + runs example_generator doctest open
Release note for pyrepl_autodoc_bootstrap removal recommended

Summary

Area Rating
Correctness (stated goals)
Scope / complexity
Tests
Docs
Upstream coupling ⚠️ pyrepl-web #5 still open
Runtime edge cases ⚠️ documented limitations

Recommendation: merge once pyrepl-web #5 lands (or accept vendoring from the PR branch with a tracked follow-up to re-vendor from grill). The design is cleaner than the original introspection approach, Phase 0 is complete, and the combined #17+#18 autodoc story is coherent. Only remaining gate is the manual RTD preview check on the live autodoc REPL example.

Open in Web Open in Cursor 

chrizzFTD and others added 2 commits July 2, 2026 21:54
* Normalize emitted asset paths for nested Sphinx pages

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: Cursor Agent <cursoragent@cursor.com>
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: #16 (current) — Local wheels, config-driven autodoc REPLs, and pyrepl-web re-vendor

Verdict: Approve. Since the last review, two meaningful commits landed (#20 path normalization, #21 test refactor). RTD preview built on 3251ca0; 47 tests pass locally.


What's new since the last review

1. Nested page paths — fixed (#20)

The earlier nit about _static/... breaking on api/module.html is resolved. The implementation uses Sphinx's relative_uri rather than root-absolute /_static/...:

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)
  • Root page: _static/wheels/foo.whl (unchanged)
  • Nested page: ../_static/wheels/foo.whl
  • PyPI names, https://, /_static/..., PEP 508 specs: unchanged

This is the right approach — idiomatic Sphinx, works with pyrepl-web's new URL() resolution. Covered by tests/unit/test_asset_href.py and tests/integration/test_nested_pages.py.

2. Test suite refactor (#21)

Tests are now layered:

Layer Examples
tests/unit/ _asset_href, autodoc_bootstrap_source, doctest_to_replay_source, config
tests/doctree/ directive output, autodoc scope
tests/integration/ full builds, autodoc wiring, nested pages, includes

Shared helpers in tests/support.py and tests/helpers.py reduce duplication. Good maintainability improvement.


What still works well

Architecturepyrepl_autodoc_packages + generated import bootstrap is clean. Three runtime layers compose correctly: install → silent import → replay.

Vendored JS — Still includes both replaySrc and resolvePackageRefs.

Docs — README now documents page-relative path rewriting (line 66). RTD preview succeeds.

Breaking changepyrepl_autodoc_bootstrap removal is appropriate pre-1.0; note in merge/release notes.


Remaining nits (non-blocking)

1. PR description is stale

The body still shows un-normalized paths in the example:

<py-repl src="_static/pyrepl/example-1-bootstrap.py"
         packages="_static/wheels/...">

And doesn't mention #20 or #21. Worth updating before merge so reviewers aren't misled. On a nested page the emitted attrs would be ../_static/....

2. Upstream: pyrepl-web #5 still open

Vendor SHA cursor/resolve-package-urls-0bbd@1d95c619 is fine stacked, but merge pyrepl-web #5 before or with this so the vendor ref is stable.

3. Wheel must match documented package

Still worth a README note: pyrepl_autodoc_packages wheel must contain the documented package.

4. Bootstrap limitations (inherent, document if not already)

Scenario Bootstrap May fail at replay
Inner class (Outer.Inner) from mod import Outer bare Inner()
Instance methods imports class only needs self / instance
Multi-package docs single config value one wheel assumed

5. Bootstrap copy still nested under replay loop

        raw_bootstrap = metadata.get(BOOTSTRAP_FILES_KEY)
        if raw_bootstrap:
            bootstrap_files = json.loads(raw_bootstrap)
            for name, content in bootstrap_files.items():
                (replay_dest / name).write_text(content, encoding="utf-8")

Always true today; separate loop would be more robust. Low priority.

6. [docs] extra clone-only

Path dependency — documented, acceptable.

7. literalinclude from tests/fixtures/

Unusual for published docs but works on RTD.


Resolved since prior review

Item Status
Nested page path normalization (#19) #20relative_uri
Test gaps for nested pages
Test suite organization #21
Replay regression from bad re-vendor
Dead register_startup_file ✓ removed earlier

Merge checklist

Step Status
pytest (47 passed)
RTD preview (3251ca0)
Nested page paths
pyrepl-web #5 merged pending upstream
PR description updated for #20/#21 recommended
Manual: autodoc REPL on docs example open
Release note: pyrepl_autodoc_bootstrap removed recommended

Summary

Area Rating
Correctness
Nested page support ✅ (improved since last review)
Tests ✅ (47, well-structured)
Docs
PR description accuracy ⚠️ stale
Upstream coupling ⚠️ pyrepl-web #5 still open

Recommendation: merge. The branch is in better shape than at the last review — nested paths and test coverage are both addressed. Only gates left are manual RTD REPL verification, syncing the PR description, and ideally landing pyrepl-web #5 alongside.

Open in Web Open in Cursor 

chrizzFTD and others added 10 commits July 5, 2026 14:24
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Breaking changes since 0.2.0: pyrepl_autodoc_bootstrap removed in favor of
pyrepl_autodoc_packages; :silent: directive option removed.

Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
Signed-off-by: Christian López Barrón <chris.gfz@gmail.com>
@chrizzFTD chrizzFTD merged commit 5b9fcee into main Jul 5, 2026
4 checks passed
@chrizzFTD chrizzFTD deleted the cursor/autodoc-bootstrap-src-only-16b5 branch July 5, 2026 22:05
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