sphinx-pyrepl-web

Python CI Documentation Status PyPI version PyPI

Sphinx extension to embed pyrepl-web in documentation.

Install

pip install sphinx-pyrepl-web

Usage

Add the extension to the target project’s conf.py module:

extensions = [
    "sphinx_pyrepl_web",
]

Embed a REPL with the py-repl directive:

.. py-repl::

.. py-repl::
   :theme: catppuccin-latte
   :no-header:

.. py-repl::
   :src: setup.py
   :packages: numpy

.. py-repl::
   :no-header:

   >>> import math
   >>> math.sqrt(16)

Directive options

All options drive pyrepl-web’s attributes:

Option

Description

:theme:

Color theme (catppuccin-mocha, catppuccin-latte)

:packages:

Comma-separated PyPI packages, URLs, relative wheel paths, or :project:

:repl-title:

Title in the REPL header

:src:

Path to a Python startup script

:replay:

Replay :src: with interactive prompts instead of silent load

:no-header:

Hide the header bar

:no-buttons:

Hide copy/clear buttons

:readonly:

Disable input

:no-banner:

Hide the Python version banner

Sphinx options

Enable doctest style examples conversion into pre-configured interactive REPLs with:

pyrepl_doctest_blocks:

Value

Outcome

False (default)

Don’t convert doctest blocks

"autodoc"

Convert doctest blocks from autodoc

"all"

Convert all doctest blocks

pyrepl_autodoc_packages:

Value

Outcome

None (default)

Replay doctest input without preloading packages

:project:

Build a wheel from the documented project and preload it

Wheel / PyPI names

Extra packages to install, e.g. ":project:,numpy"

Optional when using :project::

Value

Default

Outcome

pyrepl_project_root

auto-detect

Project root containing pyproject.toml (relative to conf.py)

pyrepl_wheel_dir

_static/wheels

Directory for the built wheel, relative to conf.py

Local wheels

Unreleased package wheels can be available in the REPL by building them under Sphinx’s html_static_path, or by using :project: to build automatically at doc-build time.

All options combined:

extensions = [
    "sphinx.ext.autodoc",
    "sphinx_pyrepl_web",
]

html_static_path = ["_static"]

pyrepl_doctest_blocks = "autodoc"
pyrepl_autodoc_packages = ":project:"

For a monorepo or non-default layout, point at the package root explicitly:

pyrepl_autodoc_packages = ":project:"
pyrepl_project_root = ".."

When the REPL needs the project wheel plus additional packages, combine them in one list:

pyrepl_autodoc_packages = ":project:, numpy"

The same :project: sentinel works in directive options:

.. py-repl::
   :packages: :project:, numpy

Examples

Basic REPL

.. py-repl::

Light theme, minimal

.. py-repl::
   :theme: catppuccin-latte
   :no-header:
   :no-banner:

Startup script

The :src: option loads a Python script into the REPL namespace. If the script defines a setup() function, its output is shown when the REPL starts.

Startup script:

message = "Hello from the startup script!"


def setup():
    print(message)
    print("Try: message")

RST content:

.. py-repl::
   :src: _static/setup.py

Rendered result:

Replay session

Inline content should follow doctest-style (>>> / ...) and is used as replay prompts.

.. py-repl::
   :no-header:
   :no-banner:

   >>> x = 2 + 2
   >>> print(f"{x=}")
   >>> x * 10
   >>> class Foo:
   ...     x = 1
   ...
   >>> Foo()

Combine a startup script with a visible replay body:

.. py-repl::
   :src: _static/setup.py
   :no-header:

   >>> print(message)

Use :replay: on :src: to source a file as replay.

Source script:

greeting = "Hello from replay mode"
print(greeting)
greeting.upper()

RST content:

.. py-repl::
   :src: _static/replay_demo.py
   :replay:
   :no-header:
   :no-banner:

Rendered result:

Local packages

Use static local wheel packages on .. py-repl:: directives:

.. py-repl::
   :packages: _static/wheels/pyrepl_test_pkg-1.0.0-py3-none-any.whl
   :no-header:
   :no-banner:

   >>> import pyrepl_test_pkg
   >>> pyrepl_test_pkg.ping()

Autodoc

Use pyrepl_doctest_blocks = "autodoc" to turn docstrings from autodoc into interactive REPL examples.

Set pyrepl_autodoc_packages to install the documented package and automatically import the documented object before replay:

# conf.py
html_static_path = ["_static"]
pyrepl_doctest_blocks = "autodoc"
pyrepl_autodoc_packages = ":project:"
pyrepl_project_root = "../tests/fixtures/pyrepl_test_pkg"

Source module:

"""Demo module for autodoc doctest REPL integration."""


def example_generator(n):
    """Generators yield values useful for iteration.

    Example:

        >>> print([i for i in example_generator(4)])
        [0, 1, 2, 3]

    """
    yield from range(n)

RST content:

.. autofunction:: pyrepl_test_pkg.demo.example_generator

Rendered result:

pyrepl_test_pkg.demo.example_generator(n)

Generators yield values useful for iteration.

Example

Development

Setup

Clone the repository, then install in editable mode with test and docs dependencies, plus the local pyrepl_test_pkg fixture used in the examples:

pip install -e ".[test,docs]"
pip install -e tests/fixtures/pyrepl_test_pkg

The [docs] extra pulls in doc build dependencies only (myst-parser). The fixture package is installed separately because PyPI packages cannot declare local path dependencies.

Build and preview docs

Build HTML output from the docs/ directory:

python -m sphinx -b html docs docs/_build

REPLs load JavaScript, replay scripts, and wheels with fetch, so they do not work when opening index.html directly from disk (file:// URLs). Serve the build output over HTTP instead:

python -m http.server --directory docs/_build

Then open http://localhost:8000/ in a browser.

Build-time behavior

Python code within a .. py-repl:: directive is written to _static/pyrepl/ at build time and emitted as replay-src.

File paths identifiers in :packages:, :src:, replay-src, and pyrepl_autodoc_packages are rewritten to page-relative URLs so REPLs work on nested pages (for example docs/api/...). PyPI package names, absolute URLs, and paths written as root-absolute (/_static/...) are left unchanged.

pyrepl_js (default: "../pyrepl.js") sets the loader script Sphinx injects on REPL pages. The extension vendors and copies pyrepl-web automatically; override this only when pointing at a custom loader path or CDN.

Static wheels

Wheel packages must be Pyodide compatible (pure-python packages work out of the box). For CPython extensions, visit pyodide-build.

Set pyrepl_autodoc_packages = ":project:" to build a wheel from the documented project automatically during the Sphinx HTML build. The wheel is written to _static/wheels/ (configurable via pyrepl_wheel_dir) and reused on incremental builds until project sources change.

Wheels under _static/ are copied into the HTML output when _static is listed in html_static_path. At runtime, pyrepl-web resolves site-relative wheel paths to absolute URLs before calling micropip.install().

Paths must use the wheel’s actual PyPI-compliant filename (for example myext-1.2.3-py3-none-any.whl). micropip rejects other names.

Ensure the web server serves .whl files with MIME type application/zip (Read the Docs does this by default).

Updating pyrepl-web

This extension vendors JavaScript from pyrepl-web’s fork for easier distribution. To refresh the vendored assets:

python scripts/vendor_repl.py

The grill branch is used by default. Pass --branch to vendor from another branch:

python scripts/vendor_repl.py --branch custom/feature-branch

This requires git and Bun.