Skip to content

Auto-build project wheel for autodoc REPLs (:project: sentinel)#25

Merged
chrizzFTD merged 4 commits into
mainfrom
cursor/auto-project-wheel-1aac
Jul 7, 2026
Merged

Auto-build project wheel for autodoc REPLs (:project: sentinel)#25
chrizzFTD merged 4 commits into
mainfrom
cursor/auto-project-wheel-1aac

Conversation

@chrizzFTD

Copy link
Copy Markdown
Owner

Summary

Implements Phase 1 of the streamlined downstream wheel workflow (closes #22).

Downstream projects can now enable autodoc REPL package preload without bespoke build scripts, RTD post_install hooks, or dynamic wheel path globs in conf.py:

extensions = ["sphinx.ext.autodoc", "sphinx_pyrepl_web"]
html_static_path = ["_static"]
pyrepl_doctest_blocks = "autodoc"
pyrepl_autodoc_packages = ":project:"

Optional overrides for monorepos or non-default layouts:

pyrepl_project_root = ".."
pyrepl_wheel_dir = "_static/wheels"

Behavior

  • On builder-inited, when pyrepl_autodoc_packages is :project::
    • Locate project root (walk up from confdir or use pyrepl_project_root)
    • Build wheel with pip wheel --no-deps into confdir/_static/wheels/
    • Reuse existing wheel when it is newer than project sources (auto incremental behavior)
    • Resolve to _static/wheels/{distribution}-{version}-….whl for micropip
  • Copy built wheels into HTML output in copy_asset_files (wheels are created after Sphinx scans static paths)
  • Existing PyPI names, URLs, and explicit wheel paths are unchanged

Tests

  • Unit tests for root detection, metadata parsing, freshness, and wheel resolution
  • Integration test building docs with :project: and no pre-built wheel copy step
  • All 61 tests pass

Docs

  • README, development.rst, and example.rst updated to document :project:
  • This repo dogfoods the sentinel via pyrepl_project_root = "../tests/fixtures/pyrepl_test_pkg"

Version

Bumps to 0.4.0 (new feature, backward compatible).

Open in Web Open in Cursor 

Introduce pyrepl_autodoc_packages = ':project:' to build a PEP 427 wheel
from the documented project during Sphinx HTML builds. Wheels are written
to _static/wheels with --no-deps, reused when sources are unchanged, and
copied into HTML output alongside other pyrepl assets.

Closes #22.

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

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

Copy link
Copy Markdown

Documentation build overview

📚 sphinx-pyrepl-web | 🛠️ Build #33478327 | 📁 Comparing d1f87c0 against latest (6fdaa91)

  🔍 Preview build  

2 files changed
± development.html
± index.html

cursoragent and others added 2 commits July 6, 2026 12:48
CI sets PYTHONWARNINGS=error globally. The pip wheel subprocess inherited
that and failed on pip's internal pkg_resources DeprecationWarning. Clear
PYTHONWARNINGS in the wheel build subprocess environment.

Co-authored-by: chrizzftd <chrizzFTD@users.noreply.github.com>
The reuse test only synced the wheel mtime to pyproject.toml, but
freshness checks all project .py files too. On CI those can be newer.

Compare mtimes at whole-second precision and set the test wheel mtime
from project_latest_mtime so reuse is asserted reliably.

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

Copy link
Copy Markdown
Owner Author

@cursoragent review

@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

PR Review: Auto-build project wheel (:project: sentinel)

Verdict: Approve — this is a solid Phase 1 implementation that directly closes #22. CI (3.12–3.14) and RTD preview are green.


What works well

API design — The sentinel is explicit and won't collide with PyPI names. Three config knobs (:project:, pyrepl_project_root, pyrepl_wheel_dir) match the refined plan without premature option creep.

Module separationwheel.py is self-contained and testable. Hook wiring in __init__.py stays minimal.

Correct hook timingbuilder-inited resolves the wheel before doctree-read / transform_doctest_blocks. The follow-up copy in copy_asset_files correctly handles wheels built after Sphinx's static-file scan — a real issue that would have broken :project: in practice.

Backward compatibility — Explicit paths, PyPI names, and URLs are untouched. Only :project: triggers new behavior.

Test coverage — Good mix of unit tests (root detection, freshness, glob matching) and an integration test that builds without copy_wheel_to(). The CI fixes (PYTHONWARNINGS isolation, mtime robustness on 3.14) show the tests are exercising real environments.

Error handlingConfigError messages are actionable (missing root, pip failure with stderr, missing wheel after build). The html_static_path warning is the right level of nudge without being too magic.


Non-blocking observations

1. Wheel copy runs unconditionally

    wheel_dir_setting = app.config.pyrepl_wheel_dir
    src_wheel_dir = Path(app.confdir) / wheel_dir_setting
    if src_wheel_dir.is_dir():
        dest_wheel_dir = outdir / wheel_dir_setting
        ...

This copies all *.whl in pyrepl_wheel_dir, even when :project: isn't used. That's reasonable (helps pre-placed wheels too), but worth a one-line doc note that the extension ensures wheels reach the output tree regardless of Sphinx static-copy timing.

2. Second-precision freshness

    wheel_mtime = int(wheel_path.stat().st_mtime)
    project_mtime = int(project_latest_mtime(project_root, wheel_dir=wheel_dir))
    return wheel_mtime >= project_mtime

A source edit and rebuild within the same second could reuse a stale wheel. Acceptable for doc builds; the comment explains the tradeoff. No change needed now.

3. setup.py-only projects

find_project_root accepts setup.py, but read_distribution_name only reads pyproject.toml / setup.cfg. Legacy setup.py-only projects would fail at name resolution. Fine for Phase 1; worth a follow-up or a note in docs.

4. Non-HTML builders

ensure_project_wheel_on_init skips non-HTML builders, so _autodoc_packages() would return the literal string :project: if someone ran e.g. latex with that config. Harmless in practice (no REPL output), but slightly inconsistent. Could log a one-time warning later.

5. docs/ excluded from freshness scan

        "doc",
        "docs",

Editing docs won't trigger a wheel rebuild. Correct for typical layouts; slightly surprising if someone keeps package code under docs/.

6. Dogfooding still needs fixture install on RTD

docs/conf.py points at the fixture package, and RTD still installs tests/fixtures/pyrepl_test_pkg separately for autodoc imports. That's expected and distinct from the wheel-for-REPL path — worth keeping explicit in development.rst so readers don't think :project: removes that step for this repo's own docs.


Docs check

README, development.rst, and example.rst all document :project: well. The RTD preview shows the updated pages. One small gap: the README could mention that pip must be available at doc-build time (implicit but worth stating for minimal CI images).


Acceptance criteria (#22)

Criterion Status
Sentinel builds wheel without consumer scripts
Nested pages via _asset_href ✅ (unchanged path)
PyPI / explicit paths unchanged
Integration test without manual wheel copy
README replaces manual CI workflow

Suggested follow-ups (post-merge, not blockers)

  1. Phase 2 — auto-default pyrepl_autodoc_packages = ":project:" when pyrepl_doctest_blocks = "autodoc"
  2. :project: on .. py-repl:: :packages: — directive-level sentinel
  3. Validate on grill-names — simplify PR #35 to drop build_docs_wheel.py
  4. CHANGELOG entry for 0.4.0 if you maintain one

Summary

This PR delivers exactly what Phase 1 promised: downstream consumers can drop bespoke wheel scripts and use three lines of config. The implementation is clean, well-tested, and the two CI fixes show good attention to real runner behavior. Recommend merge.

Open in Web Open in Cursor 

os.path.relpath raises ValueError on Windows when the fixture and the temporary srcdir live on different drives. Fall back to an absolute pyrepl_project_root in that case; find_project_root accepts absolute paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
@chrizzFTD chrizzFTD merged commit 8bc36f7 into main Jul 7, 2026
4 checks passed
@chrizzFTD chrizzFTD deleted the cursor/auto-project-wheel-1aac branch July 7, 2026 12:51
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.

Auto-build project wheel for pyrepl_autodoc_packages (eliminate per-consumer build scripts)

2 participants