sphinx-pyodide ============== .. toctree:: :hidden: changelog ``sphinx-pyodide`` is a Sphinx extension that adds a ``pyodide`` directive for embedding **executable Python code blocks** in documentation. Code runs in the browser via `Pyodide `_ (CPython compiled to WebAssembly). Installation ------------ .. code-block:: bash pip install sphinx-pyodide Enable in ``conf.py``: .. code-block:: python extensions = ["sphinx_pyodide"] Usage ----- Basic executable block ~~~~~~~~~~~~~~~~~~~~~~ Write a ``.. pyodide::`` directive with the Python code as content: .. code-block:: rst .. pyodide:: print("Hello from Pyodide!") Build-time output is displayed as static output below each block. Interactive execution requires opt-in — click **Enable Interactive** to load Pyodide and run blocks live in the browser: .. pyodide:: print("Hello from Pyodide!") With output display ~~~~~~~~~~~~~~~~~~~ .. code-block:: rst .. pyodide:: import sys print(f"Python {sys.version}") .. pyodide:: import sys print(f"Python {sys.version}") Installing packages ~~~~~~~~~~~~~~~~~~~ Use the ``:packages:`` option to install packages via micropip before running the code. .. code-block:: rst .. pyodide:: :packages: numpy import numpy as np arr = np.array([1, 2, 3, 4, 5]) print(f"mean = {arr.mean()}, sum = {arr.sum()}") .. pyodide:: :packages: numpy import numpy as np arr = np.array([1, 2, 3, 4, 5]) print(f"mean = {arr.mean()}, sum = {arr.sum()}") Multiple packages ~~~~~~~~~~~~~~~~~ .. code-block:: rst .. pyodide:: :packages: numpy, pytz from datetime import datetime import pytz tz = pytz.timezone("America/New_York") now = datetime.now(tz) print(f"New York time: {now.strftime('%H:%M:%S')}") .. pyodide:: :packages: numpy, pytz from datetime import datetime import pytz tz = pytz.timezone("America/New_York") now = datetime.now(tz) print(f"New York time: {now.strftime('%H:%M:%S')}") .. _shared-context: Shared context ~~~~~~~~~~~~~~ All ``.. pyodide::`` blocks on the same page share a single Python interpreter. Blocks execute **sequentially and in document order** — each block finishes before the next one starts. Variables, imports, and state defined in one block persist and are available to later blocks. .. code-block:: rst .. pyodide:: x = 42 .. pyodide:: print(x * 2) # accesses x from the block above; prints 84 Directives ---------- .. pyodide:: :packages: sphinx_pyodide from sphinx_pyodide.main import PyodideDirective, PyodideOutputDirective print("directives loaded") ``pyodide`` ~~~~~~~~~~~ The main directive for embedding executable Python code. .. code-block:: rst .. pyodide:: :packages: numpy :editable: import numpy as np print(np.array([1, 2, 3])) .. _pyodide-output-directive: ``pyodide-output`` ~~~~~~~~~~~~~~~~~~ Define named output for use as static output. The content is stored in the build environment and referenced by the ``:output:`` option on ``pyodide`` directives. It is displayed until the user enables interactive execution. .. code-block:: rst .. pyodide-output:: my-output Hello from Pyodide! .. pyodide:: :output: my-output print("Hello\\nfrom\\nPyodide!") The ``pyodide-output`` directive must appear before the ``pyodide`` directive that references it. Options ------- ``:packages:`` Comma-separated list of packages to install before running code. Entries ending in ``.whl`` are treated as **local wheel files** — paths are resolved relative to the source document and the files are copied into the built site automatically. .. code-block:: rst .. pyodide:: :packages: numpy, ./wheels/mylib-1.0-py3-none-any.whl import mylib mylib.hello() Place ``.whl`` files in a ``wheels/`` directory next to your source document (e.g., ``docs/source/wheels/``). They are copied into the built site automatically. Transitive PyPI dependencies declared in the wheel's metadata are resolved automatically by ``micropip`` at runtime. **Tip:** To generate wheels for packages not on PyPI: .. code-block:: bash # Your own package only uv build --wheel # Your package + all its dependencies uv pip wheel . -w wheels/ # Third-party package (download wheel from PyPI) uv pip wheel requests -w wheels/ The resulting ``.whl`` files are placed in ``dist/`` (uv build) or ``wheels/`` (pip wheel) by default. ``:output:`` Static output displayed in the output panel. Typically the expected output of the code block. Use ``\n`` for multi-line, or reference a named output block defined with the :ref:`pyodide-output-directive` directive. The static output is replaced when the user enables interactive execution. .. code-block:: rst .. pyodide:: :output: Hello, world! print("Hello, world!") .. code-block:: rst .. pyodide:: :output: Hello\nfrom\nPyodide! print("Hello\nfrom\nPyodide!") ``:show-errors:`` Flag to display runtime errors in this block's live browser output. Errors are still logged to the console regardless. .. code-block:: rst .. pyodide:: :show-errors: print(1 / 0) Overrides the global ``pyodide_show_errors`` setting for this block. ``:editable:`` Flag to make the code block editable. Users can modify the code directly in the browser before clicking **▶ Run**. ``:setup-code:`` Reference code to run before the main block. Useful for defining helper functions or imports used across multiple blocks (via :ref:`shared context `). .. code-block:: rst .. pyodide:: :setup-code: import math print(math.pi) The setup code runs in the same namespace as the block code and any earlier blocks on the page. Configuration ------------- ``pyodide_build_output`` Execute code at build time and capture stdout as static output. Defaults to ``True``. .. code-block:: python pyodide_build_output = False When enabled (default), any ``pyodide`` block without an explicit ``:output:`` option runs during ``sphinx-build``. The printed output is displayed in the output panel and remains visible until the user enables interactive execution. Clicking **Enable Interactive** runs the code live in Pyodide and replaces the static output. If the code raises an exception at build time, the error message and traceback are captured and displayed with a ``[Build-time error]`` label and distinct styling. Set to ``False`` to disable build-time capture. Blocks will show an empty output panel until the user enables interactive mode. ``pyodide_show_errors`` Show runtime errors in the live browser output. Defaults to ``False``. .. code-block:: python pyodide_show_errors = True When ``False`` (default), errors in ``pyodide`` blocks are only logged to the browser console. Set to ``True`` to display them in the output panel alongside successful results. Can be overridden per-block with the ``:show-errors:`` directive option. ``pyodide_enable_text`` HTML content for the enable banner note displayed before the first ``pyodide`` block. Defaults to a message describing the interactive blocks and static output. May contain HTML links. .. code-block:: python pyodide_enable_text = 'Run code in the browser via Pyodide.' ``pyodide_noscript_text`` Text for the noscript fallback banner, shown when JavaScript is disabled. .. code-block:: python pyodide_noscript_text = "Interactive code blocks require JavaScript." Development ----------- .. code-block:: bash git clone https://github.com/your-org/sphinx-pyodide cd sphinx-pyodide uv sync --dev Build these docs: .. code-block:: bash # Build once sphinx-build -b html docs/source docs/build # Auto-reload with live preview (recommended) sphinx-autobuild docs/source docs/build Open http://localhost:8000 in your browser. An HTTP server is required for local wheel dependencies, since micropip can not install from ``file://`` URLs due to CORS. (For projects without local wheels, browsing static html is probably be sufficient.)