Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 44 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,56 @@ Embed a REPL with the `py-repl` directive:

### Directive options

Most options drive [pyrepl-web](https://github.com/chrizzFTD/pyrepl-web)'s attributes, with a few exceptions unique to this extension:

| Option | Description | `pyrepl-web` attr? |
|--------|-------------|------------------|
| `:theme:` | Color theme (`catppuccin-mocha`, `catppuccin-latte`) | ✅ |
| `:packages:` | Comma-separated PyPI packages to preload | ✅ |
| `:repl-title:` | Title in the REPL header | ✅ |
| `:src:` | Path to a Python startup script | ✅ |
| `:replay:` | Replay `:src:` with interactive prompts instead of silent load | ✅ |
| `:silent:` | Keep `:src:` silent even when combined with a directive body | ❌ |
| `:strip-prompts:` | Strip ``>>>`` / ``...`` prefixes from directive body | ❌ |
| `:no-header:` | Hide the header bar | ✅ |
| `:no-buttons:` | Hide copy/clear buttons | ✅ |
| `:readonly:` | Disable input | ✅ |
| `:no-banner:` | Hide the Python version banner | ✅ |

Directive body content (inline Python in the `.. py-repl::` block) is also extension-only: it is written to `_static/pyrepl/` at build time and emitted as `replay-src`.
All options drive [pyrepl-web](https://github.com/chrizzFTD/pyrepl-web)'s attributes, with the exception of `silent`:

| Option | Description |
|--------|-------------|
| `:theme:` | Color theme (`catppuccin-mocha`, `catppuccin-latte`) |
| `:packages:` | Comma-separated PyPI packages to preload |
| `:repl-title:` | Title in the REPL header |
| `:src:` | Path to a Python startup script |
| `:replay:` | Replay `:src:` with interactive prompts instead of silent load |
| `:silent:` | Keep `:src:` silent even when combined with a directive body |
| `:no-header:` | Hide the header bar |
| `:no-buttons:` | Hide copy/clear buttons |
| `:readonly:` | Disable input |
| `:no-banner:` | Hide the Python version banner |

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

Optional Sphinx config:

```python
pyrepl_js = "../pyrepl.js" # default; path to the pyrepl-web loader script
pyrepl_doctest_blocks = False # default; see Docstring conversion below
pyrepl_autodoc_bootstrap = True # default; silent :src: bootstrap for autodoc REPLs
```

### Docstring conversion

Converting doctest examples from docstrings into interactive REPLs is opt-in with `sphinx.ext.autodoc`:

```python
# conf.py
extensions = [
"sphinx.ext.autodoc",
"sphinx_pyrepl_web",
]
pyrepl_doctest_blocks = "autodoc"
```

| | `pyrepl_doctest_blocks` options |
|-------------------|-------------------------------------|
| `False` (default) | Disable autodoc conversion |
| `"autodoc"` | Convert doctests found by autodoc |
| `"all"` | Transform every doctest block found |


| | `pyrepl_autodoc_bootstrap` options |
|------------------|------------------------------------------------------------------------------|
| `True` (default) | Bootstrap REPL: in-tree modules via silent `:src:`, packages via `packages=` |
| `False` | Replay doctest input only; documented names are not pre-defined |

## Updating pyrepl-web

Since [chrizzFTD/pyrepl-web](https://github.com/chrizzFTD/pyrepl-web) is a fork, this sphinx extension vendors the JavaScript assets for easier distribution. To update them, run:
Expand All @@ -81,7 +107,7 @@ python scripts/vendor_repl.py
The `grill` branch is used by default. Use the `branch` argument to specify a different one:

```bash
python scripts/vendor_repl.py --branch cursor/repl-startup-replay-2e3f
python scripts/vendor_repl.py --branch custom/feature-branch
```

This requires [git](https://git-scm.com/) and [Bun](https://bun.sh/).
12 changes: 12 additions & 0 deletions docs/_static/autodoc_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""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)
7 changes: 7 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
from datetime import date
import sys
from pathlib import Path

from sphinx_pyrepl_web import __version__

sys.path.insert(0, str(Path(__file__).parent / "_static"))

project = "sphinx-pyrepl-web"
version = __version__
author = "Christian López Barrón"
copyright = f"{date.today().year}, {author}"

extensions = [
"myst_parser",
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
"sphinx_pyrepl_web",
]
pyrepl_doctest_blocks = "autodoc"
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

html_sidebars = {
Expand Down
50 changes: 39 additions & 11 deletions docs/example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,27 @@ 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:

.. literalinclude:: _static/setup.py
:language: python

RST content:

.. code-block:: rst

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

Rendered result:

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

The startup script:

.. literalinclude:: _static/setup.py
:language: python

Replay session
--------------

Inline directive content is replayed with ``>>>`` prompts, syntax highlighting,
and live output. Doctest-style ``>>>`` / ``...`` prefixes and bare ``...``
block terminators are stripped automatically.
Inline directive content should follow Doctest-style (``>>>`` / ``...``) and is used as replay prompts.

.. code-block:: rst

Expand Down Expand Up @@ -93,7 +95,14 @@ Combine a silent bootstrap file with a visible replay body:

>>> print(message)

Use ``:replay:`` on ``:src:`` to replay a file with prompts instead of silent load:
Use ``:replay:`` on ``:src:`` to source a file as replay.

Source script:

.. literalinclude:: _static/replay_demo.py
:language: python

RST content:

.. code-block:: rst

Expand All @@ -103,13 +112,32 @@ Use ``:replay:`` on ``:src:`` to replay a file with prompts instead of silent lo
:no-header:
:no-banner:

Rendered result:

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

The replay script:
Autodoc
-------

.. literalinclude:: _static/replay_demo.py
The documented module's source is loaded in advance before replay, so
module members are available in the REPL namespace. Modules under the Sphinx
source tree use silent ``:src:``; installed packages use ``packages=``.

Source module:

.. literalinclude:: _static/autodoc_demo.py
:language: python

RST content:

.. code-block:: rst

.. autofunction:: autodoc_demo.example_generator

Rendered result:

.. autofunction:: autodoc_demo.example_generator
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,8 @@ test = [
docs = [
"myst-parser",
]

[tool.pytest.ini_options]
filterwarnings = [
"ignore:The mapping interface for autodoc options objects is deprecated:sphinx.deprecation.RemovedInSphinx11Warning",
]
Loading
Loading