sphinx-examples-as-code 0.6.0__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. sphinx_examples_as_code-0.7.0/.github/dependabot.yml +22 -0
  2. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/.github/workflows/ci.yml +22 -6
  3. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/PKG-INFO +65 -31
  4. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/README.md +60 -30
  5. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/pyproject.toml +5 -1
  6. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/sphinx_examples_as_code/__init__.py +185 -51
  7. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/sphinx_examples_as_code/_version.py +3 -3
  8. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/sphinx_examples_as_code.egg-info/PKG-INFO +65 -31
  9. sphinx_examples_as_code-0.7.0/sphinx_examples_as_code.egg-info/requires.txt +7 -0
  10. sphinx_examples_as_code-0.7.0/sphinx_examples_as_code.egg-info/scm_version.json +8 -0
  11. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/test_gallery_downloads.py +84 -11
  12. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/test_heading_level_reuse.py +7 -7
  13. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/test_single_function_page.py +5 -5
  14. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/test_sphinx_examples_as_code.py +289 -127
  15. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/test_tinypages.py +79 -67
  16. sphinx_examples_as_code-0.6.0/.github/dependabot.yml +0 -16
  17. sphinx_examples_as_code-0.6.0/sphinx_examples_as_code.egg-info/requires.txt +0 -1
  18. sphinx_examples_as_code-0.6.0/sphinx_examples_as_code.egg-info/scm_version.json +0 -8
  19. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/.github/release.yml +0 -0
  20. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/.gitignore +0 -0
  21. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/.pre-commit-config.yaml +0 -0
  22. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/LICENSE +0 -0
  23. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/setup.cfg +0 -0
  24. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/sphinx_examples_as_code.egg-info/SOURCES.txt +0 -0
  25. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/sphinx_examples_as_code.egg-info/dependency_links.txt +0 -0
  26. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/sphinx_examples_as_code.egg-info/scm_file_list.json +0 -0
  27. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/sphinx_examples_as_code.egg-info/top_level.txt +0 -0
  28. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/gallery_fixture/conf.py +0 -0
  29. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/gallery_fixture/examples/GALLERY_HEADER.rst +0 -0
  30. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/gallery_fixture/examples/plot_minimal.py +0 -0
  31. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/gallery_fixture/index.rst +0 -0
  32. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/heading_level_fixture/conf.py +0 -0
  33. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/heading_level_fixture/examples/GALLERY_HEADER.rst +0 -0
  34. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/heading_level_fixture/examples/plot_reused_level.py +0 -0
  35. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/heading_level_fixture/examples/plot_three_levels.py +0 -0
  36. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/heading_level_fixture/index.rst +0 -0
  37. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/single_function_fixture/conf.py +0 -0
  38. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/single_function_fixture/index.rst +0 -0
  39. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/single_function_fixture/mymodule.py +0 -0
  40. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/tinypages/conf.py +0 -0
  41. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/tinypages/docstring_cases.py +0 -0
  42. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/tinypages/docstring_cases.rst +0 -0
  43. {sphinx_examples_as_code-0.6.0 → sphinx_examples_as_code-0.7.0}/tests/tinypages/index.rst +0 -0
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ multi-ecosystem-groups:
3
+ maintenance:
4
+ schedule:
5
+ interval: quarterly
6
+ labels: [maintenance, dependencies]
7
+ updates:
8
+ - package-ecosystem: pip
9
+ directory: /
10
+ schedule:
11
+ interval: weekly
12
+ labels: [maintenance, dependencies]
13
+ allow:
14
+ - dependency-name: pyvista
15
+ - dependency-name: sphinx-gallery
16
+ groups:
17
+ project:
18
+ patterns: ['*']
19
+ - package-ecosystem: github-actions
20
+ directory: /
21
+ patterns: ['*']
22
+ multi-ecosystem-group: maintenance
@@ -22,10 +22,10 @@ jobs:
22
22
  with:
23
23
  persist-credentials: false
24
24
  fetch-depth: 0
25
- - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
25
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
26
26
  with:
27
27
  enable-cache: false
28
- - run: uv sync --group dev
28
+ - run: uv sync --group dev --extra gallery
29
29
  - run: uv run pre-commit run --all-files --show-diff-on-failure
30
30
  env:
31
31
  # This hook exists to stop *local* commits straight to main; it
@@ -43,15 +43,15 @@ jobs:
43
43
  with:
44
44
  persist-credentials: false
45
45
  fetch-depth: 0
46
- - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
46
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
47
47
  with:
48
48
  enable-cache: false
49
49
  - uses: pyvista/setup-headless-display-action@c103a2ff45650d38cb71684b5dc6cdfeb9442c79 # v5.1.0
50
50
  with:
51
51
  pyvista: true
52
- - run: uv sync --group dev --python ${{ matrix.python-version }}
52
+ - run: uv sync --group dev --extra gallery --python ${{ matrix.python-version }}
53
53
  - run: uv run pytest tests/ --cov --cov-report=xml
54
- - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
54
+ - uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
55
55
  with:
56
56
  files: ./coverage.xml
57
57
  env:
@@ -65,7 +65,7 @@ jobs:
65
65
  with:
66
66
  persist-credentials: false
67
67
  fetch-depth: 0
68
- - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
68
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
69
69
  with:
70
70
  enable-cache: false
71
71
  - run: uv build
@@ -87,3 +87,19 @@ jobs:
87
87
  name: dist
88
88
  path: dist/
89
89
  - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
90
+
91
+ release:
92
+ needs: publish
93
+ runs-on: ubuntu-latest
94
+ permissions:
95
+ contents: write
96
+ steps:
97
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
98
+ with:
99
+ name: dist
100
+ path: dist/
101
+ # Notes come from the merged pull requests, shaped by .github/release.yml.
102
+ - env:
103
+ GH_TOKEN: ${{ github.token }}
104
+ TAG: ${{ github.ref_name }}
105
+ run: gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --title "$TAG" --generate-notes --verify-tag dist/*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sphinx-examples-as-code
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Sphinx extension for converting docstring examples into downloadable code.
5
5
  Author-email: The PyVista Developers <info@pyvista.org>
6
6
  License-Expression: MIT
@@ -23,12 +23,17 @@ Requires-Python: >=3.10
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Requires-Dist: pyvista>=0.48
26
+ Provides-Extra: gallery
27
+ Requires-Dist: sphinx-gallery<0.23,>=0.22; extra == "gallery"
28
+ Provides-Extra: marimo
29
+ Requires-Dist: marimo>=0.14; extra == "marimo"
26
30
  Dynamic: license-file
27
31
 
28
32
  # sphinx-examples-as-code
29
33
 
30
34
  A Sphinx extension that turns docstring/page "Examples" sections into downloadable,
31
- runnable `.py` and/or `.ipynb` files, with a download link inserted into the section.
35
+ runnable Python scripts, Jupyter notebooks and/or [marimo](https://marimo.io) notebooks,
36
+ with a download link inserted into the section.
32
37
 
33
38
  Pages or docstrings without an Examples section are left completely untouched. Adding
34
39
  `sphinx_examples_as_code` to `conf.py`'s `extensions` is the only on/off switch.
@@ -39,6 +44,19 @@ Pages or docstrings without an Examples section are left completely untouched. A
39
44
  pip install sphinx-examples-as-code
40
45
  ```
41
46
 
47
+ Sphinx-Gallery integration is opt-in and needs a compatible sphinx-gallery, which the
48
+ `gallery` extra pins:
49
+
50
+ ```bash
51
+ pip install 'sphinx-examples-as-code[gallery]'
52
+ ```
53
+
54
+ marimo notebook downloads need marimo 0.14 or newer, which the `marimo` extra installs:
55
+
56
+ ```bash
57
+ pip install 'sphinx-examples-as-code[marimo]'
58
+ ```
59
+
42
60
  Add it to your Sphinx `conf.py`:
43
61
 
44
62
  ```python
@@ -56,23 +74,29 @@ the keys you want to change from their default:
56
74
  ```python
57
75
  sphinx_examples_as_code_conf = {
58
76
  'link_position': 'top',
59
- 'formats': ['py', 'ipynb'],
77
+ 'formats': ['python', 'jupyter', 'marimo'],
60
78
  'gallery_downloads': False,
61
79
  'footer': (
62
80
  'Generated by `sphinx-examples-as-code '
63
81
  '<https://github.com/pyvista/sphinx-examples-as-code>`_'
64
82
  ),
65
83
  'link_labels': {
66
- 'py': 'Download Python source code',
67
- 'ipynb': 'Download Jupyter notebook',
84
+ 'python': 'Download Python script',
85
+ 'jupyter': 'Download Jupyter notebook',
86
+ 'marimo': 'Download marimo notebook',
68
87
  },
69
88
  }
70
89
  ```
71
90
 
72
91
  - `link_position`: where the download link(s) land within the Examples section. `'top'`
73
92
  (default) or `'bottom'`.
74
- - `formats`: which downloads to generate. A list containing `'py'`, `'ipynb'`, or both
75
- (default). Always offered in that order regardless of how the list is written.
93
+ - `formats`: which downloads to generate. A list containing any of `'python'` (a plain
94
+ Python script, `<name>.py`), `'jupyter'` (a Jupyter notebook, `<name>.ipynb`) and
95
+ `'marimo'` (a marimo notebook, `<name>.marimo.py`); defaults to all three. Always
96
+ offered in that order regardless of how the list is written. Without marimo 0.14 or
97
+ newer installed, the default skips the marimo download, and a `formats` that names
98
+ `'marimo'` (in `conf.py` or through `-D`) stops the build with a configuration error. An unknown format raises a configuration error too;
99
+ the old `'py'` and `'ipynb'` names say what replaced them.
76
100
  - `link_labels`: the text of the download link(s) themselves, per format. Set only the
77
101
  format(s) you want to change; any left unset keep reading their own default shown above.
78
102
  - `gallery_downloads`: opt-in takeover of
@@ -82,11 +106,11 @@ sphinx_examples_as_code_conf = {
82
106
  - `footer`: a string appended to the end of every generated file. Defaults to a one-line
83
107
  "generated file" credit linking back to this project; set to `None` to omit it
84
108
  entirely. Preceded by a blank line and a `-`-only divider line, which also renders as a
85
- real horizontal rule in `.ipynb`; the footer always gets its own dedicated cell there.
109
+ real horizontal rule in notebooks; the footer always gets its own dedicated cell there.
86
110
  Parsed as RST: a hyperlink written as `` `text <url>`_ `` becomes a real clickable
87
- Markdown link in `.ipynb`, and renders inline as `text url` in `.py`. Plain text with no
88
- markup at all becomes one comment line per line of text, and blank-line-separated
89
- paragraphs stay separated.
111
+ Markdown link in notebooks, and renders inline as `text url` in Python scripts. Plain
112
+ text with no markup at all becomes one comment line per line of text, and
113
+ blank-line-separated paragraphs stay separated.
90
114
 
91
115
  An unrecognized key raises a configuration error at build start.
92
116
 
@@ -107,39 +131,43 @@ What happens to the content of an Examples section:
107
131
  - `.. code-block:: python` (or `py`) blocks are kept as-is; other languages become
108
132
  comments, set off with blank lines on both sides like any other directive.
109
133
  - Admonitions (`.. note::`, `.. warning::`, ...) become a `# LABEL:` comment followed by
110
- their content as comments, indented one level under the label in `.py` only.
134
+ their content as comments, indented one level under the label in Python scripts only.
111
135
  - A bullet/numbered list becomes a `-`/`N.`-marked line per item, set off with a blank
112
136
  line on both sides in either format — a bare `#` instead of a real blank line when
113
- that falls inside an admonition or a definition's own body in `.py`, so the whole
114
- thing still reads as one unbroken comment block. A definition list's term stays at
115
- the surrounding indent; its definition (the body nested under it) is indented one
116
- level further in `.py`, same as an admonition's own content.
137
+ that falls inside an admonition or a definition's own body in a Python script, so the
138
+ whole thing still reads as one unbroken comment block. A definition list's term stays
139
+ at the surrounding indent; its definition (the body nested under it) is indented one
140
+ level further in Python scripts, same as an admonition's own content.
117
141
  - Cross-references and inline code (`:class:`, `:meth:`, `:func:`, `:attr:`,
118
142
  double-backtick literals, ...) keep their display text, wrapped in backticks (e.g.
119
143
  ``:class:`pyvista.Plotter` `` -> `` `pyvista.Plotter` ``). If `html_baseurl` is set and
120
- the reference resolves, `.ipynb` turns it into a clickable link; `.py` never writes the
121
- link, only the display text.
144
+ the reference resolves, notebooks turn it into a clickable link; Python scripts never
145
+ write the link, only the display text.
122
146
  - Plain prose-style references (`:ref:`, `:doc:`) are treated the same way, minus the
123
147
  backticks.
124
148
  - Everything else text-bearing (prose, captions, other non-Python code) becomes a plain
125
149
  `#` comment.
126
150
  - A table becomes an aligned text table, its caption on the line above: an RST simple
127
- table in `.py`, a Markdown pipe table in `.ipynb`. Each cell is flattened to a single
128
- line, and a column left entirely empty -- one holding only images, say -- is dropped
129
- along with its heading.
151
+ table in Python scripts, a Markdown pipe table in notebooks. Each cell is flattened to a
152
+ single line, and a column left entirely empty -- one holding only images, say -- is
153
+ dropped along with its heading.
130
154
  - Figures/images, raw HTML, sphinx-design dropdowns/tab-sets, and sphinx-tags' `.. tags::`
131
155
  line are dropped entirely.
132
156
  - "See Also" content is always dropped.
133
157
 
134
- Generated `.py` files start with a `# Examples from <qualified name>` title header
158
+ Generated Python scripts start with a `# Examples from <qualified name>` title header
135
159
  (gallery mode uses the page's own title instead -- see below), with a few whitespace
136
160
  conventions: prose directly above a code block stays attached to it, a code block is
137
161
  always followed by a blank line, and a directive (header, `# NOTE:`-style block) gets
138
162
  blank lines on both sides.
139
163
 
140
- Generated `.ipynb` notebooks use the same content, split into alternating code/markdown
164
+ Generated Jupyter notebooks use the same content, split into alternating code/markdown
141
165
  cells instead.
142
166
 
167
+ Generated marimo notebooks are that same Jupyter notebook converted by marimo's own
168
+ converter, the one behind `marimo convert`. `from __future__` imports are dropped first,
169
+ so the notebook also runs as a plain script (`python <name>.marimo.py`).
170
+
143
171
  A download link is only added if the resulting code contains at least one real
144
172
  executable statement.
145
173
 
@@ -148,7 +176,7 @@ executable statement.
148
176
  With `sphinx_examples_as_code_conf['gallery_downloads'] = True`, this extension takes
149
177
  over the downloads on every page generated by
150
178
  [sphinx-gallery](https://sphinx-gallery.github.io): the "Go to the end to download the
151
- full example code" note and the `.py`/`.ipynb`/`.zip` download footer are removed from
179
+ full example code" note and the `.py`/`.zip` download footer are removed from
152
180
  the page, replaced with download link(s) built by this extension instead — same
153
181
  conversion rules as above, applied to the whole page rather than one Examples section.
154
182
  The generated file's header uses the page's own title (e.g. `# Create Circular Arcs`)
@@ -163,7 +191,7 @@ is left completely untouched. Gallery pages and ordinary docstring/prose pages (
163
191
  the Examples-section behavior above) can coexist on the same site.
164
192
 
165
193
  A `# %%` cell with its own RST heading gets the same header treatment as the file's own
166
- title, and renders as a real Markdown heading in `.ipynb`. Level is relative to actual
194
+ title, and renders as a real Markdown heading in notebooks. Level is relative to actual
167
195
  RST section nesting, not always one below the file's own header: a cell heading nested
168
196
  under the page's own title (the common case) is one level below it; one that reuses the
169
197
  page title's own underline character is level 1, the same as the file's own header; a
@@ -172,24 +200,30 @@ cell heading nested under *that* is level 2 relative to it, and so on.
172
200
  Each format uses one heading style consistently across every level, rather than mixing
173
201
  styles:
174
202
 
175
- - `.py` uses an RST-style title + underline, one character per level -- the same
203
+ - Python scripts use an RST-style title + underline, one character per level -- the same
176
204
  sequence Sphinx's own documentation uses for sections through sub-paragraphs: `=`, `-`,
177
205
  `~`, `^`, `"`, `'` for levels 1 through 6.
178
- - `.ipynb` always uses ATX syntax (`#`, `##`, `###`, ...) at every level.
206
+ - Notebooks always use ATX syntax (`#`, `##`, `###`, ...) at every level.
179
207
 
180
208
  Two things worth knowing before turning this on:
181
209
 
182
210
  - It's built against sphinx-gallery's own doctree output — the `sphx-glr-*` CSS classes
183
211
  its own theming depends on, and the private node type holding a highlighted code
184
212
  block — not a documented extension API. A future sphinx-gallery release could shift
185
- that structure without warning. Tested against sphinx-gallery 0.22 and later.
186
- - sphinx-gallery's own `.py`/`.ipynb`/`.zip` downloads still end up copied into
187
- `_downloads/`, even though nothing on the page links to them anymore.
213
+ that structure without warning. Only sphinx-gallery 0.22.x is tested, so the `gallery`
214
+ extra caps there rather than letting the next release quietly produce no downloads.
215
+ - sphinx-gallery's own `.py`/`.zip` downloads still end up copied into `_downloads/`,
216
+ even though nothing on the page links to them anymore. Its `.ipynb` is never written:
217
+ with `gallery_downloads` on, this extension sets `sphinx_gallery_conf['pypandoc']` to
218
+ `False` and `sphinx_gallery_conf['notebook_extensions']` to an empty set before
219
+ sphinx-gallery reads them, so pandoc is not needed. Setting `pypandoc`,
220
+ `notebook_extensions`, `first_notebook_cell`, `last_notebook_cell` or `notebook_images`
221
+ yourself has no effect and is reported as a warning.
188
222
 
189
223
  ## Development
190
224
 
191
225
  ```bash
192
- uv sync --group dev
226
+ uv sync --group dev --extra gallery
193
227
  uv run pytest
194
228
  uv run pre-commit run --all-files
195
229
  ```
@@ -1,7 +1,8 @@
1
1
  # sphinx-examples-as-code
2
2
 
3
3
  A Sphinx extension that turns docstring/page "Examples" sections into downloadable,
4
- runnable `.py` and/or `.ipynb` files, with a download link inserted into the section.
4
+ runnable Python scripts, Jupyter notebooks and/or [marimo](https://marimo.io) notebooks,
5
+ with a download link inserted into the section.
5
6
 
6
7
  Pages or docstrings without an Examples section are left completely untouched. Adding
7
8
  `sphinx_examples_as_code` to `conf.py`'s `extensions` is the only on/off switch.
@@ -12,6 +13,19 @@ Pages or docstrings without an Examples section are left completely untouched. A
12
13
  pip install sphinx-examples-as-code
13
14
  ```
14
15
 
16
+ Sphinx-Gallery integration is opt-in and needs a compatible sphinx-gallery, which the
17
+ `gallery` extra pins:
18
+
19
+ ```bash
20
+ pip install 'sphinx-examples-as-code[gallery]'
21
+ ```
22
+
23
+ marimo notebook downloads need marimo 0.14 or newer, which the `marimo` extra installs:
24
+
25
+ ```bash
26
+ pip install 'sphinx-examples-as-code[marimo]'
27
+ ```
28
+
15
29
  Add it to your Sphinx `conf.py`:
16
30
 
17
31
  ```python
@@ -29,23 +43,29 @@ the keys you want to change from their default:
29
43
  ```python
30
44
  sphinx_examples_as_code_conf = {
31
45
  'link_position': 'top',
32
- 'formats': ['py', 'ipynb'],
46
+ 'formats': ['python', 'jupyter', 'marimo'],
33
47
  'gallery_downloads': False,
34
48
  'footer': (
35
49
  'Generated by `sphinx-examples-as-code '
36
50
  '<https://github.com/pyvista/sphinx-examples-as-code>`_'
37
51
  ),
38
52
  'link_labels': {
39
- 'py': 'Download Python source code',
40
- 'ipynb': 'Download Jupyter notebook',
53
+ 'python': 'Download Python script',
54
+ 'jupyter': 'Download Jupyter notebook',
55
+ 'marimo': 'Download marimo notebook',
41
56
  },
42
57
  }
43
58
  ```
44
59
 
45
60
  - `link_position`: where the download link(s) land within the Examples section. `'top'`
46
61
  (default) or `'bottom'`.
47
- - `formats`: which downloads to generate. A list containing `'py'`, `'ipynb'`, or both
48
- (default). Always offered in that order regardless of how the list is written.
62
+ - `formats`: which downloads to generate. A list containing any of `'python'` (a plain
63
+ Python script, `<name>.py`), `'jupyter'` (a Jupyter notebook, `<name>.ipynb`) and
64
+ `'marimo'` (a marimo notebook, `<name>.marimo.py`); defaults to all three. Always
65
+ offered in that order regardless of how the list is written. Without marimo 0.14 or
66
+ newer installed, the default skips the marimo download, and a `formats` that names
67
+ `'marimo'` (in `conf.py` or through `-D`) stops the build with a configuration error. An unknown format raises a configuration error too;
68
+ the old `'py'` and `'ipynb'` names say what replaced them.
49
69
  - `link_labels`: the text of the download link(s) themselves, per format. Set only the
50
70
  format(s) you want to change; any left unset keep reading their own default shown above.
51
71
  - `gallery_downloads`: opt-in takeover of
@@ -55,11 +75,11 @@ sphinx_examples_as_code_conf = {
55
75
  - `footer`: a string appended to the end of every generated file. Defaults to a one-line
56
76
  "generated file" credit linking back to this project; set to `None` to omit it
57
77
  entirely. Preceded by a blank line and a `-`-only divider line, which also renders as a
58
- real horizontal rule in `.ipynb`; the footer always gets its own dedicated cell there.
78
+ real horizontal rule in notebooks; the footer always gets its own dedicated cell there.
59
79
  Parsed as RST: a hyperlink written as `` `text <url>`_ `` becomes a real clickable
60
- Markdown link in `.ipynb`, and renders inline as `text url` in `.py`. Plain text with no
61
- markup at all becomes one comment line per line of text, and blank-line-separated
62
- paragraphs stay separated.
80
+ Markdown link in notebooks, and renders inline as `text url` in Python scripts. Plain
81
+ text with no markup at all becomes one comment line per line of text, and
82
+ blank-line-separated paragraphs stay separated.
63
83
 
64
84
  An unrecognized key raises a configuration error at build start.
65
85
 
@@ -80,39 +100,43 @@ What happens to the content of an Examples section:
80
100
  - `.. code-block:: python` (or `py`) blocks are kept as-is; other languages become
81
101
  comments, set off with blank lines on both sides like any other directive.
82
102
  - Admonitions (`.. note::`, `.. warning::`, ...) become a `# LABEL:` comment followed by
83
- their content as comments, indented one level under the label in `.py` only.
103
+ their content as comments, indented one level under the label in Python scripts only.
84
104
  - A bullet/numbered list becomes a `-`/`N.`-marked line per item, set off with a blank
85
105
  line on both sides in either format — a bare `#` instead of a real blank line when
86
- that falls inside an admonition or a definition's own body in `.py`, so the whole
87
- thing still reads as one unbroken comment block. A definition list's term stays at
88
- the surrounding indent; its definition (the body nested under it) is indented one
89
- level further in `.py`, same as an admonition's own content.
106
+ that falls inside an admonition or a definition's own body in a Python script, so the
107
+ whole thing still reads as one unbroken comment block. A definition list's term stays
108
+ at the surrounding indent; its definition (the body nested under it) is indented one
109
+ level further in Python scripts, same as an admonition's own content.
90
110
  - Cross-references and inline code (`:class:`, `:meth:`, `:func:`, `:attr:`,
91
111
  double-backtick literals, ...) keep their display text, wrapped in backticks (e.g.
92
112
  ``:class:`pyvista.Plotter` `` -> `` `pyvista.Plotter` ``). If `html_baseurl` is set and
93
- the reference resolves, `.ipynb` turns it into a clickable link; `.py` never writes the
94
- link, only the display text.
113
+ the reference resolves, notebooks turn it into a clickable link; Python scripts never
114
+ write the link, only the display text.
95
115
  - Plain prose-style references (`:ref:`, `:doc:`) are treated the same way, minus the
96
116
  backticks.
97
117
  - Everything else text-bearing (prose, captions, other non-Python code) becomes a plain
98
118
  `#` comment.
99
119
  - A table becomes an aligned text table, its caption on the line above: an RST simple
100
- table in `.py`, a Markdown pipe table in `.ipynb`. Each cell is flattened to a single
101
- line, and a column left entirely empty -- one holding only images, say -- is dropped
102
- along with its heading.
120
+ table in Python scripts, a Markdown pipe table in notebooks. Each cell is flattened to a
121
+ single line, and a column left entirely empty -- one holding only images, say -- is
122
+ dropped along with its heading.
103
123
  - Figures/images, raw HTML, sphinx-design dropdowns/tab-sets, and sphinx-tags' `.. tags::`
104
124
  line are dropped entirely.
105
125
  - "See Also" content is always dropped.
106
126
 
107
- Generated `.py` files start with a `# Examples from <qualified name>` title header
127
+ Generated Python scripts start with a `# Examples from <qualified name>` title header
108
128
  (gallery mode uses the page's own title instead -- see below), with a few whitespace
109
129
  conventions: prose directly above a code block stays attached to it, a code block is
110
130
  always followed by a blank line, and a directive (header, `# NOTE:`-style block) gets
111
131
  blank lines on both sides.
112
132
 
113
- Generated `.ipynb` notebooks use the same content, split into alternating code/markdown
133
+ Generated Jupyter notebooks use the same content, split into alternating code/markdown
114
134
  cells instead.
115
135
 
136
+ Generated marimo notebooks are that same Jupyter notebook converted by marimo's own
137
+ converter, the one behind `marimo convert`. `from __future__` imports are dropped first,
138
+ so the notebook also runs as a plain script (`python <name>.marimo.py`).
139
+
116
140
  A download link is only added if the resulting code contains at least one real
117
141
  executable statement.
118
142
 
@@ -121,7 +145,7 @@ executable statement.
121
145
  With `sphinx_examples_as_code_conf['gallery_downloads'] = True`, this extension takes
122
146
  over the downloads on every page generated by
123
147
  [sphinx-gallery](https://sphinx-gallery.github.io): the "Go to the end to download the
124
- full example code" note and the `.py`/`.ipynb`/`.zip` download footer are removed from
148
+ full example code" note and the `.py`/`.zip` download footer are removed from
125
149
  the page, replaced with download link(s) built by this extension instead — same
126
150
  conversion rules as above, applied to the whole page rather than one Examples section.
127
151
  The generated file's header uses the page's own title (e.g. `# Create Circular Arcs`)
@@ -136,7 +160,7 @@ is left completely untouched. Gallery pages and ordinary docstring/prose pages (
136
160
  the Examples-section behavior above) can coexist on the same site.
137
161
 
138
162
  A `# %%` cell with its own RST heading gets the same header treatment as the file's own
139
- title, and renders as a real Markdown heading in `.ipynb`. Level is relative to actual
163
+ title, and renders as a real Markdown heading in notebooks. Level is relative to actual
140
164
  RST section nesting, not always one below the file's own header: a cell heading nested
141
165
  under the page's own title (the common case) is one level below it; one that reuses the
142
166
  page title's own underline character is level 1, the same as the file's own header; a
@@ -145,24 +169,30 @@ cell heading nested under *that* is level 2 relative to it, and so on.
145
169
  Each format uses one heading style consistently across every level, rather than mixing
146
170
  styles:
147
171
 
148
- - `.py` uses an RST-style title + underline, one character per level -- the same
172
+ - Python scripts use an RST-style title + underline, one character per level -- the same
149
173
  sequence Sphinx's own documentation uses for sections through sub-paragraphs: `=`, `-`,
150
174
  `~`, `^`, `"`, `'` for levels 1 through 6.
151
- - `.ipynb` always uses ATX syntax (`#`, `##`, `###`, ...) at every level.
175
+ - Notebooks always use ATX syntax (`#`, `##`, `###`, ...) at every level.
152
176
 
153
177
  Two things worth knowing before turning this on:
154
178
 
155
179
  - It's built against sphinx-gallery's own doctree output — the `sphx-glr-*` CSS classes
156
180
  its own theming depends on, and the private node type holding a highlighted code
157
181
  block — not a documented extension API. A future sphinx-gallery release could shift
158
- that structure without warning. Tested against sphinx-gallery 0.22 and later.
159
- - sphinx-gallery's own `.py`/`.ipynb`/`.zip` downloads still end up copied into
160
- `_downloads/`, even though nothing on the page links to them anymore.
182
+ that structure without warning. Only sphinx-gallery 0.22.x is tested, so the `gallery`
183
+ extra caps there rather than letting the next release quietly produce no downloads.
184
+ - sphinx-gallery's own `.py`/`.zip` downloads still end up copied into `_downloads/`,
185
+ even though nothing on the page links to them anymore. Its `.ipynb` is never written:
186
+ with `gallery_downloads` on, this extension sets `sphinx_gallery_conf['pypandoc']` to
187
+ `False` and `sphinx_gallery_conf['notebook_extensions']` to an empty set before
188
+ sphinx-gallery reads them, so pandoc is not needed. Setting `pypandoc`,
189
+ `notebook_extensions`, `first_notebook_cell`, `last_notebook_cell` or `notebook_images`
190
+ yourself has no effect and is reported as a warning.
161
191
 
162
192
  ## Development
163
193
 
164
194
  ```bash
165
- uv sync --group dev
195
+ uv sync --group dev --extra gallery
166
196
  uv run pytest
167
197
  uv run pre-commit run --all-files
168
198
  ```
@@ -4,6 +4,7 @@ requires = ['setuptools>=64', 'setuptools_scm>=8']
4
4
 
5
5
  [dependency-groups]
6
6
  dev = [
7
+ 'marimo>=0.14',
7
8
  'nbformat',
8
9
  'numpydoc',
9
10
  'pre-commit',
@@ -11,7 +12,6 @@ dev = [
11
12
  'pytest-cov',
12
13
  'sphinx',
13
14
  'sphinx-design',
14
- 'sphinx-gallery>=0.22',
15
15
  'trame-pyvista',
16
16
  ]
17
17
 
@@ -41,6 +41,10 @@ name = 'sphinx-examples-as-code'
41
41
  readme = 'README.md'
42
42
  requires-python = '>=3.10'
43
43
 
44
+ [project.optional-dependencies]
45
+ gallery = ['sphinx-gallery>=0.22,<0.23']
46
+ marimo = ['marimo>=0.14']
47
+
44
48
  [project.urls]
45
49
  Homepage = 'https://github.com/pyvista/sphinx-examples-as-code'
46
50