Metadata-Version: 2.4
Name: sphinx-examples-as-code
Version: 0.2.1
Summary: Sphinx extension for converting docstring examples into downloadable code.
Author-email: The PyVista Developers <info@pyvista.org>
License-Expression: MIT
Project-URL: Homepage, https://github.com/pyvista/sphinx-examples-as-code
Keywords: download,examples,sphinx
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Sphinx :: Extension
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: pyvista>=0.48

# sphinx-examples-as-code

A Sphinx extension that turns docstring/page "Examples" sections into downloadable,
runnable `.py` and/or `.ipynb` files, with a download link inserted into the section.

Pages or docstrings without an Examples section are left completely untouched. Adding
`sphinx_examples_as_code` to `conf.py`'s `extensions` is the only on/off switch.

## Installation

```bash
pip install sphinx-examples-as-code
```

Add it to your Sphinx `conf.py`:

```python
extensions = [
    ...,
    'sphinx_examples_as_code',
]
```

## Configuration

Everything lives in one dict in `conf.py`, `sphinx_examples_as_code_conf` -- set only
the keys you want to change from their default:

```python
sphinx_examples_as_code_conf = {
    'link_position': 'top',
    'formats': ['py', 'ipynb'],
    'base_url': None,
    'gallery_downloads': False,
    'footer': (
        'Generated by `sphinx-examples-as-code '
        '<https://github.com/pyvista/sphinx-examples-as-code>`_'
    ),
}
```

- `link_position`: where the download link(s) land within the Examples section. `'top'`
  (default) or `'bottom'`.
- `formats`: which downloads to generate. A list containing `'py'`, `'ipynb'`, or both
  (default). Always offered in that order regardless of how the list is written.
- `base_url`: the site's published base URL (e.g. `'https://docs.pyvista.org/'`), used
  to turn cross-references into absolute links a downloaded, standalone file can
  actually use. `None` (default) means no links are generated anywhere. A missing
  trailing slash is added automatically; a value with no scheme or host raises a
  configuration error at build start.
- `gallery_downloads`: opt-in takeover of
  [sphinx-gallery](https://sphinx-gallery.github.io)'s own per-example downloads.
  `False` (default) leaves sphinx-gallery pages untouched. See
  [Sphinx-Gallery integration](#sphinx-gallery-integration) below.
- `footer`: a string appended to the end of every generated file. Defaults to a one-line
  "generated file" credit linking back to this project; set to `None` to omit it
  entirely. Preceded by a blank line and a `-`-only divider line, marking it as trailing
  boilerplate rather than more of the example's own commentary -- the divider also
  renders as a real horizontal rule in `.ipynb`, where the footer always gets its own
  dedicated cell, regardless of what content precedes it. Parsed as RST, the same as any
  other prose this extension handles: a hyperlink written as `` `text <url>`_ `` becomes
  a real clickable Markdown link in `.ipynb`, and renders inline as `text url` in `.py`.
  Plain text with no markup at all becomes one comment line per line of text, and
  blank-line-separated paragraphs stay separated -- a longer, multi-paragraph custom
  footer is laid out the same way any other prose in this extension is.

An unrecognized key (a typo, or a leftover from an older release) raises a configuration
error at build start rather than silently doing nothing.

Overriding a single key from the command line works via a dotted `-D` flag, e.g.
`-D sphinx_examples_as_code_conf.link_position=bottom` -- this only touches that one
key, leaving the rest (`conf.py`'s values, or the defaults) alone.

## Conversion rules

What happens to the content of an Examples section:

- Doctest blocks (`>>> ...` / `... ...`) keep their input lines, prompts stripped, as
  real Python source. Doctest *output* lines are dropped — only the input code matters.
- `.. code-block:: python` (or `py`) blocks are kept as-is; other languages become
  comments, set off with blank lines on both sides like any other directive -- so a
  preformatted block (e.g. an RST `::`-block illustrating a data format) still reads as
  a distinct block rather than melting into the surrounding prose.
- Admonitions (`.. note::`, `.. warning::`, `.. seealso::`, ...) become a `# LABEL:`
  comment followed by their content as comments. "See Also" is recognized in any of its
  three forms (`.. seealso::`, a bare `.. rubric:: See Also`, or a hand-written `See
  Also` heading) and always renders the same way.
- Cross-references and inline code (`:class:`, `:meth:`, `:func:`, `:attr:`,
  double-backtick literals, ...) keep their display text, wrapped in backticks (e.g.
  ``:class:`pyvista.Plotter` `` -> `` `pyvista.Plotter` ``). If `base_url` is set and
  the reference resolves: `.ipynb` turns it into a clickable link everywhere; `.py` only
  writes the link inside a "See Also" part (as `name url` on its own line) — everywhere
  else in `.py` the link is simply omitted.
- Plain prose-style references (`:ref:`, `:doc:`) are treated the same way, minus the
  backticks.
- Everything else text-bearing (prose, captions, other non-Python code) becomes a plain
  `#` comment.
- Figures/images, raw HTML, sphinx-design dropdowns/tab-sets, and sphinx-tags' `.. tags::`
  line are dropped entirely -- none of them are documentation content a downloaded,
  standalone file has any use for.

Generated `.py` files start with a `# Examples from <qualified name>` title header
(gallery mode uses the page's own title instead -- see below) and follow a few
whitespace conventions so the result reads like normal Python: prose
directly above a code block stays attached to it, a code block is always followed by a
blank line, and a directive (header, `# NOTE:`-style block) gets blank lines on both
sides.

Generated `.ipynb` notebooks use the same content, split into alternating code/markdown
cells instead.

A download link is only added if the resulting code contains at least one real
executable statement.

## Sphinx-Gallery integration

With `sphinx_examples_as_code_conf['gallery_downloads'] = True`, this extension takes
over the downloads on every page generated by
[sphinx-gallery](https://sphinx-gallery.github.io): the "Go to the end to download the
full example code" note and the `.py`/`.ipynb`/`.zip` download footer are removed from
the page, replaced with download link(s) built by this extension instead — same
conversion rules as above, applied to the whole page rather than one Examples section.
The generated file's header uses the page's own title (e.g. `# Create Circular Arcs`)
rather than the generic `# Examples from <docname>` — gallery mode converts the whole
page, not an Examples section carved out of a larger docstring, so there's no "from"
framing to make.

The "Total running time" line and the "Gallery generated by Sphinx-Gallery" credit line
stay on the rendered page untouched, but never make it into the generated download
itself: a "Total running time" sitting inside a file you just downloaded and ran
yourself would read like it's timing *your* run, not the build's, and a "Generated by
Sphinx-Gallery" credit is simply wrong inside a file this extension generated.

Detection is automatic and per-page — any page without a sphinx-gallery download footer
is left completely untouched, so turning this on is safe even on a site that mixes
gallery pages with ordinary docstring/prose pages using the Examples-section behavior
above.

A `# %%` cell with its own RST heading gets the same title-plus-underline treatment as
the file's own header, rather than melting into whatever prose follows it -- and for
that reason renders as a real Markdown heading in `.ipynb`, not just plain text.

Two things worth knowing before turning this on:

- It's built against sphinx-gallery's own long-standing RST/HTML output (the same
  `sphx-glr-*` CSS classes its own theming depends on), not a documented extension API.
  It's unlikely to change, but a future sphinx-gallery release could still shift that
  structure without warning.
- sphinx-gallery registers its own `.py`/`.ipynb`/`.zip` downloads for copying into
  `_downloads/` before this extension gets a chance to remove the links pointing to
  them, so those files still end up in the build output even though nothing on the page
  links to them anymore.

## Development

```bash
uv sync --group dev
uv run pytest
uv run pre-commit run --all-files
```
