sphinx-examples-as-code 0.8.0__tar.gz → 0.8.2__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.
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/PKG-INFO +14 -9
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/README.md +13 -8
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code/__init__.py +99 -15
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code/_version.py +3 -3
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code.egg-info/PKG-INFO +14 -9
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code.egg-info/scm_version.json +2 -2
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_gallery_downloads.py +1 -1
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_single_function_page.py +2 -2
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_sphinx_examples_as_code.py +93 -2
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_tinypages.py +12 -24
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/.github/dependabot.yml +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/.github/release.yml +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/.github/workflows/ci.yml +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/.gitignore +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/.pre-commit-config.yaml +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/LICENSE +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/pyproject.toml +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/setup.cfg +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code.egg-info/SOURCES.txt +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code.egg-info/dependency_links.txt +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code.egg-info/requires.txt +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code.egg-info/scm_file_list.json +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code.egg-info/top_level.txt +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/gallery_fixture/conf.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/gallery_fixture/examples/GALLERY_HEADER.rst +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/gallery_fixture/examples/plot_minimal.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/gallery_fixture/index.rst +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/heading_level_fixture/conf.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/heading_level_fixture/examples/GALLERY_HEADER.rst +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/heading_level_fixture/examples/plot_reused_level.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/heading_level_fixture/examples/plot_three_levels.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/heading_level_fixture/index.rst +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/single_function_fixture/conf.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/single_function_fixture/index.rst +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/single_function_fixture/mymodule.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_heading_level_reuse.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/tinypages/conf.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/tinypages/docstring_cases.py +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/tinypages/docstring_cases.rst +0 -0
- {sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/tinypages/index.rst +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sphinx-examples-as-code
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
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
|
|
@@ -96,11 +96,13 @@ sphinx_examples_as_code_conf = {
|
|
|
96
96
|
(default) or `'bottom'`.
|
|
97
97
|
- `formats`: which downloads to generate. A list containing any of `'python'` (a plain
|
|
98
98
|
Python script, `<name>.py`), `'jupyter'` (a Jupyter notebook, `<name>.ipynb`) and
|
|
99
|
-
`'marimo'` (a marimo notebook, `<name
|
|
99
|
+
`'marimo'` (a marimo notebook, `<name>_marimo.py`); defaults to all three. Always
|
|
100
100
|
offered in that order regardless of how the list is written. Without marimo 0.14 or
|
|
101
101
|
newer installed, the default skips the marimo download, and a `formats` that names
|
|
102
102
|
`'marimo'` (in `conf.py` or through `-D`) stops the build with a configuration error. An unknown format raises a configuration error too;
|
|
103
|
-
the old `'py'` and `'ipynb'` names say what replaced them.
|
|
103
|
+
the old `'py'` and `'ipynb'` names say what replaced them. `<name>` is the documented
|
|
104
|
+
object's full name without its top-level package, e.g. `Plotter_show` for
|
|
105
|
+
`pyvista.Plotter.show`, or the gallery example's file name.
|
|
104
106
|
- `link_labels`: the text of the download link(s) themselves, per format. Set only the
|
|
105
107
|
format(s) you want to change; any left unset keep reading their own default shown above.
|
|
106
108
|
- `gallery_downloads`: opt-in takeover of
|
|
@@ -149,8 +151,9 @@ imports, plus any `dependencies` set for its format, and says how to run it:
|
|
|
149
151
|
needed, so the command works in bash, zsh, PowerShell and cmd. An argument containing
|
|
150
152
|
`"`, `$`, a backtick, `\`, `%` or a `!` not followed by `=` is single-quoted instead,
|
|
151
153
|
which cmd does not understand.
|
|
152
|
-
- marimo notebooks start with the same `# /// script` block, which also lists `marimo
|
|
153
|
-
|
|
154
|
+
- marimo notebooks start with the same `# /// script` block, which also lists `marimo`
|
|
155
|
+
unless another dependency installs it,
|
|
156
|
+
followed by `# Open this notebook with: uvx marimo edit --sandbox <name>_marimo.py`.
|
|
154
157
|
- Each run command is followed by a line linking to
|
|
155
158
|
[uv's installation guide](https://docs.astral.sh/uv/getting-started/installation/).
|
|
156
159
|
|
|
@@ -158,7 +161,9 @@ Imports are read from the code, not run. Each imported top-level module maps to
|
|
|
158
161
|
project that provides it in the environment building the docs; standard-library
|
|
159
162
|
modules, relative imports and modules no single installed project provides are left
|
|
160
163
|
out. Projects the code needs but never imports, such as an optional backend, go in
|
|
161
|
-
`dependencies`.
|
|
164
|
+
`dependencies`. A dependency with no version or extras of its own is left out when another listed
|
|
165
|
+
one already installs it on every platform, e.g. `numpy` and `marimo` next to
|
|
166
|
+
`pyvista[marimo]`.
|
|
162
167
|
|
|
163
168
|
The project named by Sphinx's own `project` setting (e.g. `project = 'PyVista'`) gets
|
|
164
169
|
extra treatment when an example imports it and it is installed: its dependency becomes
|
|
@@ -169,8 +174,8 @@ Unless `requires_python` is set, the block's `requires-python` combines:
|
|
|
169
174
|
|
|
170
175
|
- that project's own `Requires-Python`, e.g. `>=3.10`, when it is listed;
|
|
171
176
|
- `<3.N`, one minor version above the newest Python named in the `Programming Language ::
|
|
172
|
-
Python :: 3.X` classifiers of that project and of every listed
|
|
173
|
-
from a platform-specific wheel, as installed in the environment building the docs.
|
|
177
|
+
Python :: 3.X` classifiers of that project and of every dependency, listed or left out,
|
|
178
|
+
installed from a platform-specific wheel, as installed in the environment building the docs.
|
|
174
179
|
Pure-Python dependencies and dependencies without such classifiers don't count, and
|
|
175
180
|
the bound is dropped when it would exclude every Python the project's own
|
|
176
181
|
`Requires-Python` allows.
|
|
@@ -221,7 +226,7 @@ cells instead.
|
|
|
221
226
|
|
|
222
227
|
Generated marimo notebooks are that same Jupyter notebook converted by marimo's own
|
|
223
228
|
converter, the one behind `marimo convert`. `from __future__` imports are dropped first,
|
|
224
|
-
so the notebook also runs as a plain script (`python <name
|
|
229
|
+
so the notebook also runs as a plain script (`python <name>_marimo.py`).
|
|
225
230
|
|
|
226
231
|
A download link is only added if the resulting code contains at least one real
|
|
227
232
|
executable statement.
|
|
@@ -64,11 +64,13 @@ sphinx_examples_as_code_conf = {
|
|
|
64
64
|
(default) or `'bottom'`.
|
|
65
65
|
- `formats`: which downloads to generate. A list containing any of `'python'` (a plain
|
|
66
66
|
Python script, `<name>.py`), `'jupyter'` (a Jupyter notebook, `<name>.ipynb`) and
|
|
67
|
-
`'marimo'` (a marimo notebook, `<name
|
|
67
|
+
`'marimo'` (a marimo notebook, `<name>_marimo.py`); defaults to all three. Always
|
|
68
68
|
offered in that order regardless of how the list is written. Without marimo 0.14 or
|
|
69
69
|
newer installed, the default skips the marimo download, and a `formats` that names
|
|
70
70
|
`'marimo'` (in `conf.py` or through `-D`) stops the build with a configuration error. An unknown format raises a configuration error too;
|
|
71
|
-
the old `'py'` and `'ipynb'` names say what replaced them.
|
|
71
|
+
the old `'py'` and `'ipynb'` names say what replaced them. `<name>` is the documented
|
|
72
|
+
object's full name without its top-level package, e.g. `Plotter_show` for
|
|
73
|
+
`pyvista.Plotter.show`, or the gallery example's file name.
|
|
72
74
|
- `link_labels`: the text of the download link(s) themselves, per format. Set only the
|
|
73
75
|
format(s) you want to change; any left unset keep reading their own default shown above.
|
|
74
76
|
- `gallery_downloads`: opt-in takeover of
|
|
@@ -117,8 +119,9 @@ imports, plus any `dependencies` set for its format, and says how to run it:
|
|
|
117
119
|
needed, so the command works in bash, zsh, PowerShell and cmd. An argument containing
|
|
118
120
|
`"`, `$`, a backtick, `\`, `%` or a `!` not followed by `=` is single-quoted instead,
|
|
119
121
|
which cmd does not understand.
|
|
120
|
-
- marimo notebooks start with the same `# /// script` block, which also lists `marimo
|
|
121
|
-
|
|
122
|
+
- marimo notebooks start with the same `# /// script` block, which also lists `marimo`
|
|
123
|
+
unless another dependency installs it,
|
|
124
|
+
followed by `# Open this notebook with: uvx marimo edit --sandbox <name>_marimo.py`.
|
|
122
125
|
- Each run command is followed by a line linking to
|
|
123
126
|
[uv's installation guide](https://docs.astral.sh/uv/getting-started/installation/).
|
|
124
127
|
|
|
@@ -126,7 +129,9 @@ Imports are read from the code, not run. Each imported top-level module maps to
|
|
|
126
129
|
project that provides it in the environment building the docs; standard-library
|
|
127
130
|
modules, relative imports and modules no single installed project provides are left
|
|
128
131
|
out. Projects the code needs but never imports, such as an optional backend, go in
|
|
129
|
-
`dependencies`.
|
|
132
|
+
`dependencies`. A dependency with no version or extras of its own is left out when another listed
|
|
133
|
+
one already installs it on every platform, e.g. `numpy` and `marimo` next to
|
|
134
|
+
`pyvista[marimo]`.
|
|
130
135
|
|
|
131
136
|
The project named by Sphinx's own `project` setting (e.g. `project = 'PyVista'`) gets
|
|
132
137
|
extra treatment when an example imports it and it is installed: its dependency becomes
|
|
@@ -137,8 +142,8 @@ Unless `requires_python` is set, the block's `requires-python` combines:
|
|
|
137
142
|
|
|
138
143
|
- that project's own `Requires-Python`, e.g. `>=3.10`, when it is listed;
|
|
139
144
|
- `<3.N`, one minor version above the newest Python named in the `Programming Language ::
|
|
140
|
-
Python :: 3.X` classifiers of that project and of every listed
|
|
141
|
-
from a platform-specific wheel, as installed in the environment building the docs.
|
|
145
|
+
Python :: 3.X` classifiers of that project and of every dependency, listed or left out,
|
|
146
|
+
installed from a platform-specific wheel, as installed in the environment building the docs.
|
|
142
147
|
Pure-Python dependencies and dependencies without such classifiers don't count, and
|
|
143
148
|
the bound is dropped when it would exclude every Python the project's own
|
|
144
149
|
`Requires-Python` allows.
|
|
@@ -189,7 +194,7 @@ cells instead.
|
|
|
189
194
|
|
|
190
195
|
Generated marimo notebooks are that same Jupyter notebook converted by marimo's own
|
|
191
196
|
converter, the one behind `marimo convert`. `from __future__` imports are dropped first,
|
|
192
|
-
so the notebook also runs as a plain script (`python <name
|
|
197
|
+
so the notebook also runs as a plain script (`python <name>_marimo.py`).
|
|
193
198
|
|
|
194
199
|
A download link is only added if the resulting code contains at least one real
|
|
195
200
|
executable statement.
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code/__init__.py
RENAMED
|
@@ -7,6 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import ast
|
|
9
9
|
from dataclasses import dataclass
|
|
10
|
+
from dataclasses import replace
|
|
10
11
|
import functools
|
|
11
12
|
import hashlib
|
|
12
13
|
import importlib.metadata
|
|
@@ -181,6 +182,9 @@ _FMT_PYTHON = 'python'
|
|
|
181
182
|
_FMT_JUPYTER = 'jupyter'
|
|
182
183
|
_FMT_MARIMO = 'marimo'
|
|
183
184
|
|
|
185
|
+
#: File name suffix of each download format, e.g. ``pyvista_read_marimo.py``.
|
|
186
|
+
_SUFFIXES = {_FMT_PYTHON: '.py', _FMT_JUPYTER: '.ipynb', _FMT_MARIMO: '_marimo.py'}
|
|
187
|
+
|
|
184
188
|
|
|
185
189
|
@dataclass(frozen=True)
|
|
186
190
|
class _RenderContext:
|
|
@@ -805,6 +809,14 @@ def _qualified_name_for(node: nodes.Node, docname: str, counter: int) -> str:
|
|
|
805
809
|
return f'{base}-example-{counter}'
|
|
806
810
|
|
|
807
811
|
|
|
812
|
+
def _download_stem(node: nodes.Node, docname: str, counter: int) -> str:
|
|
813
|
+
"""Name a span's downloads, e.g. ``Plotter.show`` for ``pyvista.Plotter.show``."""
|
|
814
|
+
name = _qualified_name_for(node, docname, counter)
|
|
815
|
+
if any(_desc_id(desc) is not None for desc in _enclosing_descs(node)):
|
|
816
|
+
return name.partition('.')[2] or name
|
|
817
|
+
return name
|
|
818
|
+
|
|
819
|
+
|
|
808
820
|
def _header_title(qualified_name: str) -> str:
|
|
809
821
|
"""Build the file's own header title text, e.g. ``Examples from pyvista.read``."""
|
|
810
822
|
return f'Examples from {qualified_name}'
|
|
@@ -931,13 +943,13 @@ def _build_notebook(cells: list[tuple[str, list[str]]]) -> dict:
|
|
|
931
943
|
}
|
|
932
944
|
|
|
933
945
|
|
|
934
|
-
def _download_filename(name: str,
|
|
935
|
-
"""Return the file name a download is written under, e.g. ``
|
|
946
|
+
def _download_filename(name: str, fmt: str) -> str:
|
|
947
|
+
"""Return the file name a download is written under, e.g. ``Plotter_show.py``."""
|
|
936
948
|
safe_name = name.replace('.', '_') if name else 'example'
|
|
937
|
-
return f'{safe_name}
|
|
949
|
+
return f'{safe_name}{_SUFFIXES[fmt]}'
|
|
938
950
|
|
|
939
951
|
|
|
940
|
-
def _write_download_file(app: Sphinx, name: str,
|
|
952
|
+
def _write_download_file(app: Sphinx, name: str, fmt: str, content: str) -> str:
|
|
941
953
|
"""Write generated content directly into the builder's downloads dir.
|
|
942
954
|
|
|
943
955
|
Returns the written file's path relative to the downloads directory --
|
|
@@ -948,7 +960,7 @@ def _write_download_file(app: Sphinx, name: str, extension: str, content: str) -
|
|
|
948
960
|
"""
|
|
949
961
|
# 32 hex chars, matching Sphinx's own native _downloads/<digest>/... layout.
|
|
950
962
|
digest = hashlib.sha256(content.encode()).hexdigest()[:32]
|
|
951
|
-
filename = _download_filename(name,
|
|
963
|
+
filename = _download_filename(name, fmt)
|
|
952
964
|
rel_path = f'{digest}/{filename}'
|
|
953
965
|
|
|
954
966
|
out_path = Path(app.outdir) / '_downloads' / digest / filename
|
|
@@ -959,12 +971,23 @@ def _write_download_file(app: Sphinx, name: str, extension: str, content: str) -
|
|
|
959
971
|
|
|
960
972
|
def _write_python_script(app: Sphinx, name: str, source: str) -> str:
|
|
961
973
|
"""Write a generated Python script; see ``_write_download_file``."""
|
|
962
|
-
return _write_download_file(app, name,
|
|
974
|
+
return _write_download_file(app, name, _FMT_PYTHON, source)
|
|
963
975
|
|
|
964
976
|
|
|
965
977
|
def _write_jupyter_notebook(app: Sphinx, name: str, notebook: dict) -> str:
|
|
966
978
|
"""Write a generated Jupyter notebook; see ``_write_download_file``."""
|
|
967
|
-
return _write_download_file(app, name,
|
|
979
|
+
return _write_download_file(app, name, _FMT_JUPYTER, json.dumps(notebook, indent=1))
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
def _title_first(cells: list) -> list:
|
|
983
|
+
"""Move marimo's leading ``import marimo as mo`` cell below the title cell after it."""
|
|
984
|
+
if (
|
|
985
|
+
len(cells) > 1
|
|
986
|
+
and cells[0].code == 'import marimo as mo'
|
|
987
|
+
and cells[1].code.startswith('mo.md(')
|
|
988
|
+
):
|
|
989
|
+
return [cells[1], cells[0], *cells[2:]]
|
|
990
|
+
return cells
|
|
968
991
|
|
|
969
992
|
|
|
970
993
|
def _drop_future_imports(source: list[str]) -> list[str]:
|
|
@@ -994,8 +1017,9 @@ def _write_marimo_notebook(app: Sphinx, name: str, notebook: dict, header: str =
|
|
|
994
1017
|
else cell
|
|
995
1018
|
for cell in notebook['cells']
|
|
996
1019
|
]
|
|
997
|
-
|
|
998
|
-
|
|
1020
|
+
ir = MarimoConvert.from_ipynb(json.dumps({**notebook, 'cells': cells})).to_ir()
|
|
1021
|
+
source = MarimoConvert.from_ir(replace(ir, cells=_title_first(ir.cells))).to_py()
|
|
1022
|
+
return _write_download_file(app, name, _FMT_MARIMO, header + source)
|
|
999
1023
|
|
|
1000
1024
|
|
|
1001
1025
|
@functools.cache
|
|
@@ -1067,6 +1091,66 @@ def _keep_pin(requirement: str, pin: str | None) -> str:
|
|
|
1067
1091
|
return str(parsed)
|
|
1068
1092
|
|
|
1069
1093
|
|
|
1094
|
+
_QUOTED = re.compile(r'"[^"]*"|\'[^\']*\'')
|
|
1095
|
+
_MARKER_WORDS = {'and', 'or', 'not', 'in'}
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
def _depends_only_on_extras(requirement: Requirement, extras: frozenset[str]) -> bool:
|
|
1099
|
+
"""Check whether ``requirement`` applies with ``extras`` on every platform and Python."""
|
|
1100
|
+
if requirement.marker is None:
|
|
1101
|
+
return True
|
|
1102
|
+
names = set(re.findall(r'[A-Za-z_.]+', _QUOTED.sub('', str(requirement.marker))))
|
|
1103
|
+
if names - _MARKER_WORDS != {'extra'}:
|
|
1104
|
+
return False
|
|
1105
|
+
return any(requirement.marker.evaluate({'extra': extra}) for extra in extras | {''})
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
@functools.cache
|
|
1109
|
+
def _installed_requirements(name: str, extras: frozenset[str]) -> frozenset[Requirement]:
|
|
1110
|
+
"""Return the unconditional requirements of an installed distribution with ``extras``."""
|
|
1111
|
+
try:
|
|
1112
|
+
requires = importlib.metadata.requires(name) or []
|
|
1113
|
+
except importlib.metadata.PackageNotFoundError:
|
|
1114
|
+
return frozenset()
|
|
1115
|
+
parsed = (Requirement(req) for req in requires)
|
|
1116
|
+
return frozenset(req for req in parsed if _depends_only_on_extras(req, extras))
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
def _transitive_names(requirement: str) -> set[str]:
|
|
1120
|
+
"""Return the normalized names every install of ``requirement`` pulls in, itself excluded."""
|
|
1121
|
+
root = Requirement(requirement)
|
|
1122
|
+
seen: set[tuple[str, frozenset[str]]] = set()
|
|
1123
|
+
todo = [(canonicalize_name(root.name), frozenset(root.extras))]
|
|
1124
|
+
names: set[str] = set()
|
|
1125
|
+
while todo:
|
|
1126
|
+
key = todo.pop()
|
|
1127
|
+
if key in seen:
|
|
1128
|
+
continue
|
|
1129
|
+
seen.add(key)
|
|
1130
|
+
for req in _installed_requirements(*key):
|
|
1131
|
+
names.add(canonicalize_name(req.name))
|
|
1132
|
+
todo.append((canonicalize_name(req.name), frozenset(req.extras)))
|
|
1133
|
+
names.discard(canonicalize_name(root.name))
|
|
1134
|
+
return names
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
def _drop_covered(deps: list[str]) -> list[str]:
|
|
1138
|
+
"""Drop each bare-name dependency that another listed dependency already installs."""
|
|
1139
|
+
pulled = {dep: _transitive_names(dep) for dep in deps}
|
|
1140
|
+
names = {dep: _canonical_name(dep) for dep in deps}
|
|
1141
|
+
|
|
1142
|
+
def covered(dep: str) -> bool:
|
|
1143
|
+
if dep != Requirement(dep).name:
|
|
1144
|
+
return False
|
|
1145
|
+
return any(
|
|
1146
|
+
names[dep] in pulled[other] and names[other] not in pulled[dep]
|
|
1147
|
+
for other in deps
|
|
1148
|
+
if other != dep
|
|
1149
|
+
)
|
|
1150
|
+
|
|
1151
|
+
return [dep for dep in deps if not covered(dep)]
|
|
1152
|
+
|
|
1153
|
+
|
|
1070
1154
|
@dataclass(frozen=True)
|
|
1071
1155
|
class _DocumentedProject:
|
|
1072
1156
|
"""The installed distribution named by Sphinx's ``project``."""
|
|
@@ -1294,28 +1378,28 @@ def _build_download_entries(
|
|
|
1294
1378
|
cap = _python_upper_bound(deps[fmt], project.name if project else None)
|
|
1295
1379
|
return _python_range(floor, cap)
|
|
1296
1380
|
|
|
1381
|
+
shown = {fmt: _drop_covered(fmt_deps) for fmt, fmt_deps in deps.items()}
|
|
1382
|
+
|
|
1297
1383
|
def header_for(fmt: str, run_line: str) -> str:
|
|
1298
1384
|
if not deps:
|
|
1299
1385
|
return ''
|
|
1300
|
-
return _script_metadata_header(
|
|
1386
|
+
return _script_metadata_header(shown[fmt], requires_python_for(fmt), run_line)
|
|
1301
1387
|
|
|
1302
1388
|
entries = []
|
|
1303
1389
|
for fmt in _FORMAT_ORDER:
|
|
1304
1390
|
if fmt not in formats:
|
|
1305
1391
|
continue
|
|
1306
1392
|
label = link_labels[fmt]
|
|
1393
|
+
filename = _download_filename(name, fmt)
|
|
1307
1394
|
if fmt == _FMT_PYTHON:
|
|
1308
|
-
filename = _download_filename(name, 'py')
|
|
1309
1395
|
header = header_for(fmt, f'Run this script with: uv run {filename}')
|
|
1310
1396
|
rel_path = _write_python_script(app, name, header + source)
|
|
1311
1397
|
elif fmt == _FMT_JUPYTER:
|
|
1312
|
-
filename = _download_filename(name, 'ipynb')
|
|
1313
1398
|
run_line = (
|
|
1314
|
-
_jupyter_run_line(
|
|
1399
|
+
_jupyter_run_line(shown[fmt], requires_python_for(fmt), filename) if deps else None
|
|
1315
1400
|
)
|
|
1316
1401
|
rel_path = _write_jupyter_notebook(app, name, notebook_for(run_line))
|
|
1317
1402
|
else:
|
|
1318
|
-
filename = _download_filename(name, 'marimo.py')
|
|
1319
1403
|
run_line = f'Open this notebook with: uvx marimo edit --sandbox {filename}'
|
|
1320
1404
|
rel_path = _write_marimo_notebook(
|
|
1321
1405
|
app, name, notebook_for(None), header_for(fmt, run_line)
|
|
@@ -1346,7 +1430,7 @@ def _process_span(
|
|
|
1346
1430
|
entries = _build_download_entries(
|
|
1347
1431
|
app,
|
|
1348
1432
|
docname,
|
|
1349
|
-
|
|
1433
|
+
_download_stem(heading, docname, counter),
|
|
1350
1434
|
_header_title(name),
|
|
1351
1435
|
nodes_in_span,
|
|
1352
1436
|
formats,
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/sphinx_examples_as_code/_version.py
RENAMED
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.8.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 8,
|
|
21
|
+
__version__ = version = '0.8.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 8, 2)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g69288337b'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sphinx-examples-as-code
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
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
|
|
@@ -96,11 +96,13 @@ sphinx_examples_as_code_conf = {
|
|
|
96
96
|
(default) or `'bottom'`.
|
|
97
97
|
- `formats`: which downloads to generate. A list containing any of `'python'` (a plain
|
|
98
98
|
Python script, `<name>.py`), `'jupyter'` (a Jupyter notebook, `<name>.ipynb`) and
|
|
99
|
-
`'marimo'` (a marimo notebook, `<name
|
|
99
|
+
`'marimo'` (a marimo notebook, `<name>_marimo.py`); defaults to all three. Always
|
|
100
100
|
offered in that order regardless of how the list is written. Without marimo 0.14 or
|
|
101
101
|
newer installed, the default skips the marimo download, and a `formats` that names
|
|
102
102
|
`'marimo'` (in `conf.py` or through `-D`) stops the build with a configuration error. An unknown format raises a configuration error too;
|
|
103
|
-
the old `'py'` and `'ipynb'` names say what replaced them.
|
|
103
|
+
the old `'py'` and `'ipynb'` names say what replaced them. `<name>` is the documented
|
|
104
|
+
object's full name without its top-level package, e.g. `Plotter_show` for
|
|
105
|
+
`pyvista.Plotter.show`, or the gallery example's file name.
|
|
104
106
|
- `link_labels`: the text of the download link(s) themselves, per format. Set only the
|
|
105
107
|
format(s) you want to change; any left unset keep reading their own default shown above.
|
|
106
108
|
- `gallery_downloads`: opt-in takeover of
|
|
@@ -149,8 +151,9 @@ imports, plus any `dependencies` set for its format, and says how to run it:
|
|
|
149
151
|
needed, so the command works in bash, zsh, PowerShell and cmd. An argument containing
|
|
150
152
|
`"`, `$`, a backtick, `\`, `%` or a `!` not followed by `=` is single-quoted instead,
|
|
151
153
|
which cmd does not understand.
|
|
152
|
-
- marimo notebooks start with the same `# /// script` block, which also lists `marimo
|
|
153
|
-
|
|
154
|
+
- marimo notebooks start with the same `# /// script` block, which also lists `marimo`
|
|
155
|
+
unless another dependency installs it,
|
|
156
|
+
followed by `# Open this notebook with: uvx marimo edit --sandbox <name>_marimo.py`.
|
|
154
157
|
- Each run command is followed by a line linking to
|
|
155
158
|
[uv's installation guide](https://docs.astral.sh/uv/getting-started/installation/).
|
|
156
159
|
|
|
@@ -158,7 +161,9 @@ Imports are read from the code, not run. Each imported top-level module maps to
|
|
|
158
161
|
project that provides it in the environment building the docs; standard-library
|
|
159
162
|
modules, relative imports and modules no single installed project provides are left
|
|
160
163
|
out. Projects the code needs but never imports, such as an optional backend, go in
|
|
161
|
-
`dependencies`.
|
|
164
|
+
`dependencies`. A dependency with no version or extras of its own is left out when another listed
|
|
165
|
+
one already installs it on every platform, e.g. `numpy` and `marimo` next to
|
|
166
|
+
`pyvista[marimo]`.
|
|
162
167
|
|
|
163
168
|
The project named by Sphinx's own `project` setting (e.g. `project = 'PyVista'`) gets
|
|
164
169
|
extra treatment when an example imports it and it is installed: its dependency becomes
|
|
@@ -169,8 +174,8 @@ Unless `requires_python` is set, the block's `requires-python` combines:
|
|
|
169
174
|
|
|
170
175
|
- that project's own `Requires-Python`, e.g. `>=3.10`, when it is listed;
|
|
171
176
|
- `<3.N`, one minor version above the newest Python named in the `Programming Language ::
|
|
172
|
-
Python :: 3.X` classifiers of that project and of every listed
|
|
173
|
-
from a platform-specific wheel, as installed in the environment building the docs.
|
|
177
|
+
Python :: 3.X` classifiers of that project and of every dependency, listed or left out,
|
|
178
|
+
installed from a platform-specific wheel, as installed in the environment building the docs.
|
|
174
179
|
Pure-Python dependencies and dependencies without such classifiers don't count, and
|
|
175
180
|
the bound is dropped when it would exclude every Python the project's own
|
|
176
181
|
`Requires-Python` allows.
|
|
@@ -221,7 +226,7 @@ cells instead.
|
|
|
221
226
|
|
|
222
227
|
Generated marimo notebooks are that same Jupyter notebook converted by marimo's own
|
|
223
228
|
converter, the one behind `marimo convert`. `from __future__` imports are dropped first,
|
|
224
|
-
so the notebook also runs as a plain script (`python <name
|
|
229
|
+
so the notebook also runs as a plain script (`python <name>_marimo.py`).
|
|
225
230
|
|
|
226
231
|
A download link is only added if the resulting code contains at least one real
|
|
227
232
|
executable statement.
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_gallery_downloads.py
RENAMED
|
@@ -275,7 +275,7 @@ def test_gallery_downloads_generated_python_executes(gallery_build: tuple[Path,
|
|
|
275
275
|
def test_gallery_downloads_marimo_notebook_executes(gallery_build: tuple[Path, str]):
|
|
276
276
|
"""The marimo notebook holds the page's code and runs as a plain script."""
|
|
277
277
|
html_dir, _html = gallery_build
|
|
278
|
-
(marimo_path,) = (html_dir / '_downloads').rglob('
|
|
278
|
+
(marimo_path,) = (html_dir / '_downloads').rglob('*_marimo.py')
|
|
279
279
|
src = marimo_path.read_text(encoding='utf-8')
|
|
280
280
|
assert 'app = marimo.App(' in src
|
|
281
281
|
assert 'A minimal gallery example' in src
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_single_function_page.py
RENAMED
|
@@ -29,12 +29,12 @@ def test_download_named_after_the_function_not_the_docname(tmp_path: Path):
|
|
|
29
29
|
assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
|
|
30
30
|
|
|
31
31
|
downloads_dir = html_dir / '_downloads'
|
|
32
|
-
python_files = [p for p in downloads_dir.rglob('*.py') if not p.name.endswith('.
|
|
32
|
+
python_files = [p for p in downloads_dir.rglob('*.py') if not p.name.endswith('_marimo.py')]
|
|
33
33
|
assert len(python_files) == 1, f'expected exactly one generated .py, got {python_files}'
|
|
34
34
|
python_path = python_files[0]
|
|
35
35
|
|
|
36
36
|
# not "index-example-1" (the docname-derived fallback name)
|
|
37
|
-
assert python_path.stem == '
|
|
37
|
+
assert python_path.stem == 'download_bunny'
|
|
38
38
|
|
|
39
39
|
lines = python_path.read_text(encoding='utf-8').splitlines()
|
|
40
40
|
assert lines[0] == '# Examples from mymodule.download_bunny'
|
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import copy
|
|
11
11
|
import json
|
|
12
|
+
from types import SimpleNamespace
|
|
12
13
|
from typing import TYPE_CHECKING
|
|
13
14
|
from unittest.mock import Mock
|
|
14
15
|
|
|
@@ -1140,6 +1141,24 @@ def test_qualified_name_for_desc_ancestor():
|
|
|
1140
1141
|
assert seac._qualified_name_for(heading, 'page', 1) == 'pkg.mod.func'
|
|
1141
1142
|
|
|
1142
1143
|
|
|
1144
|
+
@pytest.mark.parametrize(('desc_id', 'expected'), [('pkg.mod.func', 'mod.func'), ('func', 'func')])
|
|
1145
|
+
def test_download_stem_drops_top_level_package(desc_id: str, expected: str):
|
|
1146
|
+
desc = addnodes.desc()
|
|
1147
|
+
desc += addnodes.desc_signature(ids=[desc_id])
|
|
1148
|
+
content = addnodes.desc_content()
|
|
1149
|
+
heading = nodes.rubric()
|
|
1150
|
+
content += heading
|
|
1151
|
+
desc += content
|
|
1152
|
+
assert seac._download_stem(heading, 'page', 1) == expected
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
def test_download_stem_keeps_dotted_fallback_name():
|
|
1156
|
+
section = nodes.section()
|
|
1157
|
+
heading = nodes.rubric()
|
|
1158
|
+
section += heading
|
|
1159
|
+
assert seac._download_stem(heading, 'release.0.44', 1) == 'release.0.44-example-1'
|
|
1160
|
+
|
|
1161
|
+
|
|
1143
1162
|
def test_qualified_name_for_fallback_no_desc_ancestor():
|
|
1144
1163
|
section = nodes.section()
|
|
1145
1164
|
heading = nodes.rubric()
|
|
@@ -1613,6 +1632,18 @@ def test_build_notebook_valid_nbformat():
|
|
|
1613
1632
|
nbformat.validate(node) # raises if invalid
|
|
1614
1633
|
|
|
1615
1634
|
|
|
1635
|
+
@pytest.mark.parametrize(
|
|
1636
|
+
('name', 'fmt', 'expected'),
|
|
1637
|
+
[
|
|
1638
|
+
('ImageDataFilters.resample', 'marimo', 'ImageDataFilters_resample_marimo.py'),
|
|
1639
|
+
('plot_vtk9.4', 'python', 'plot_vtk9_4.py'),
|
|
1640
|
+
('', 'jupyter', 'example.ipynb'),
|
|
1641
|
+
],
|
|
1642
|
+
)
|
|
1643
|
+
def test_download_filename(name: str, fmt: str, expected: str):
|
|
1644
|
+
assert seac._download_filename(name, fmt) == expected
|
|
1645
|
+
|
|
1646
|
+
|
|
1616
1647
|
# ---------------------------------------------------------------------------
|
|
1617
1648
|
# _write_jupyter_notebook
|
|
1618
1649
|
# ---------------------------------------------------------------------------
|
|
@@ -1856,8 +1887,8 @@ def test_process_span_footer_in_notebook_is_linkified(tmp_path: Path):
|
|
|
1856
1887
|
(['jupyter'], ['.ipynb']),
|
|
1857
1888
|
(['python', 'jupyter'], ['.py', '.ipynb']),
|
|
1858
1889
|
(['jupyter', 'python'], ['.py', '.ipynb']), # canonical order regardless of config order
|
|
1859
|
-
(['marimo'], ['.
|
|
1860
|
-
(['marimo', 'python', 'jupyter'], ['.py', '.ipynb', '.
|
|
1890
|
+
(['marimo'], ['_marimo.py']),
|
|
1891
|
+
(['marimo', 'python', 'jupyter'], ['.py', '.ipynb', '_marimo.py']),
|
|
1861
1892
|
([], []),
|
|
1862
1893
|
],
|
|
1863
1894
|
)
|
|
@@ -3052,6 +3083,21 @@ def test_script_metadata_marimo(tmp_path: Path):
|
|
|
3052
3083
|
)
|
|
3053
3084
|
assert source.startswith(header)
|
|
3054
3085
|
assert 'Open this notebook' not in source.removeprefix(header)
|
|
3086
|
+
assert source.index('mo.md(') < source.index('import marimo as mo')
|
|
3087
|
+
|
|
3088
|
+
|
|
3089
|
+
@pytest.mark.parametrize(
|
|
3090
|
+
('codes', 'expected'),
|
|
3091
|
+
[
|
|
3092
|
+
(['import marimo as mo', 'mo.md("# T")', 'x = 1'], [1, 0, 2]),
|
|
3093
|
+
(['import marimo as mo', 'x = 1'], [0, 1]),
|
|
3094
|
+
(['mo.md("# T")', 'import marimo as mo'], [0, 1]),
|
|
3095
|
+
(['import marimo as mo'], [0]),
|
|
3096
|
+
],
|
|
3097
|
+
)
|
|
3098
|
+
def test_title_first(codes: list[str], expected: list[int]):
|
|
3099
|
+
cells = [SimpleNamespace(code=code) for code in codes]
|
|
3100
|
+
assert seac._title_first(cells) == [cells[i] for i in expected]
|
|
3055
3101
|
|
|
3056
3102
|
|
|
3057
3103
|
def test_process_doctree_script_metadata_enabled(tmp_path: Path):
|
|
@@ -3203,3 +3249,48 @@ def test_script_metadata_documented_project_not_imported(
|
|
|
3203
3249
|
source = _python_source_for(tmp_path, 'NumPy', '.. rubric:: Examples\n\n>>> import docutils')
|
|
3204
3250
|
assert '# requires-python = "<3.15"\n' in source
|
|
3205
3251
|
assert 'numpy' not in source
|
|
3252
|
+
|
|
3253
|
+
|
|
3254
|
+
@pytest.fixture
|
|
3255
|
+
def fake_requires(monkeypatch: pytest.MonkeyPatch):
|
|
3256
|
+
"""Serve installed requirements from a dict."""
|
|
3257
|
+
|
|
3258
|
+
def install(requires: dict[str, list[str]]) -> None:
|
|
3259
|
+
def fake(name: str) -> list[str]:
|
|
3260
|
+
if name not in requires:
|
|
3261
|
+
raise seac.importlib.metadata.PackageNotFoundError(name)
|
|
3262
|
+
return requires[name]
|
|
3263
|
+
|
|
3264
|
+
monkeypatch.setattr(seac.importlib.metadata, 'requires', fake)
|
|
3265
|
+
|
|
3266
|
+
seac._installed_requirements.cache_clear()
|
|
3267
|
+
yield install
|
|
3268
|
+
seac._installed_requirements.cache_clear()
|
|
3269
|
+
|
|
3270
|
+
|
|
3271
|
+
def test_drop_covered_follows_extras_transitively(fake_requires):
|
|
3272
|
+
fake_requires(
|
|
3273
|
+
{
|
|
3274
|
+
'pyvista': ['numpy>=1.21', 'trame-pyvista[marimo]>=0.3; extra == "marimo"'],
|
|
3275
|
+
'trame-pyvista': ['marimo; extra == "marimo"'],
|
|
3276
|
+
}
|
|
3277
|
+
)
|
|
3278
|
+
deps = ['marimo', 'numpy', 'pyvista[marimo]', 'scipy']
|
|
3279
|
+
assert seac._drop_covered(deps) == ['pyvista[marimo]', 'scipy']
|
|
3280
|
+
assert seac._drop_covered(['marimo', 'numpy', 'pyvista']) == ['marimo', 'pyvista']
|
|
3281
|
+
|
|
3282
|
+
|
|
3283
|
+
def test_drop_covered_keeps_pinned_platform_specific_and_cycles(fake_requires):
|
|
3284
|
+
fake_requires(
|
|
3285
|
+
{
|
|
3286
|
+
'pyvista': ['numpy', 'pooch; sys_platform == "linux"', 'cycle'],
|
|
3287
|
+
'cycle': ['pyvista'],
|
|
3288
|
+
}
|
|
3289
|
+
)
|
|
3290
|
+
deps = ['cycle', 'numpy>=2', 'pooch', 'pyvista']
|
|
3291
|
+
assert seac._drop_covered(deps) == deps
|
|
3292
|
+
|
|
3293
|
+
|
|
3294
|
+
def test_drop_covered_without_metadata_keeps_everything(fake_requires):
|
|
3295
|
+
fake_requires({})
|
|
3296
|
+
assert seac._drop_covered(['numpy', 'pyvista']) == ['numpy', 'pyvista']
|
|
@@ -92,7 +92,7 @@ def built(tmp_path_factory) -> tuple[Path, list[Path]]:
|
|
|
92
92
|
assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
|
|
93
93
|
|
|
94
94
|
downloads_dir = html_dir / '_downloads'
|
|
95
|
-
examples = sorted(p for p in downloads_dir.rglob('*.py') if not p.name.endswith('.
|
|
95
|
+
examples = sorted(p for p in downloads_dir.rglob('*.py') if not p.name.endswith('_marimo.py'))
|
|
96
96
|
return html_dir, examples
|
|
97
97
|
|
|
98
98
|
|
|
@@ -228,7 +228,7 @@ def test_table_becomes_an_rst_simple_table_in_python(built: tuple[Path, list[Pat
|
|
|
228
228
|
|
|
229
229
|
def test_table_becomes_a_markdown_table_in_jupyter(built_jupyter_notebooks: list[Path]):
|
|
230
230
|
"""The same table is a Markdown pipe table in a notebook's markdown cell."""
|
|
231
|
-
nb_path = next(p for p in built_jupyter_notebooks if p.stem == '
|
|
231
|
+
nb_path = next(p for p in built_jupyter_notebooks if p.stem == 'case_table')
|
|
232
232
|
notebook = json.loads(nb_path.read_text(encoding='utf-8'))
|
|
233
233
|
lines = [
|
|
234
234
|
line.rstrip()
|
|
@@ -246,9 +246,7 @@ def test_table_becomes_a_markdown_table_in_jupyter(built_jupyter_notebooks: list
|
|
|
246
246
|
|
|
247
247
|
def test_header_less_table_gets_a_blank_markdown_header(built_jupyter_notebooks: list[Path]):
|
|
248
248
|
"""A Markdown pipe table needs a header row, so one is left blank."""
|
|
249
|
-
nb_path = next(
|
|
250
|
-
p for p in built_jupyter_notebooks if p.stem == 'docstring_cases_case_table_without_header'
|
|
251
|
-
)
|
|
249
|
+
nb_path = next(p for p in built_jupyter_notebooks if p.stem == 'case_table_without_header')
|
|
252
250
|
notebook = json.loads(nb_path.read_text(encoding='utf-8'))
|
|
253
251
|
lines = [
|
|
254
252
|
line.rstrip()
|
|
@@ -301,7 +299,7 @@ def test_header_format(built: tuple[Path, list[Path]]):
|
|
|
301
299
|
|
|
302
300
|
def test_header_format_jupyter_uses_atx(built_jupyter_notebooks: list[Path]):
|
|
303
301
|
"""The same header, in .ipynb, is a single ATX level-1 line -- no underline."""
|
|
304
|
-
nb_path = next(p for p in built_jupyter_notebooks if p.stem == '
|
|
302
|
+
nb_path = next(p for p in built_jupyter_notebooks if p.stem == 'case_note')
|
|
305
303
|
notebook = json.loads(nb_path.read_text(encoding='utf-8'))
|
|
306
304
|
header_cell = notebook['cells'][0]
|
|
307
305
|
lines = [line.rstrip() for line in header_cell['source']]
|
|
@@ -451,9 +449,7 @@ def test_jupyter_notebook_code_cells_match_python_code(
|
|
|
451
449
|
line for line in python_src.splitlines() if line and not line.startswith('#')
|
|
452
450
|
]
|
|
453
451
|
|
|
454
|
-
notebook_path = next(
|
|
455
|
-
p for p in built_jupyter_notebooks if p.stem == 'docstring_cases_case_combined'
|
|
456
|
-
)
|
|
452
|
+
notebook_path = next(p for p in built_jupyter_notebooks if p.stem == 'case_combined')
|
|
457
453
|
notebook = json.loads(notebook_path.read_text(encoding='utf-8'))
|
|
458
454
|
code_cells = [c for c in notebook['cells'] if c['cell_type'] == 'code']
|
|
459
455
|
notebook_code_lines = [
|
|
@@ -494,7 +490,7 @@ def test_formats_config_selection(
|
|
|
494
490
|
assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
|
|
495
491
|
|
|
496
492
|
downloads_dir = html_dir / '_downloads'
|
|
497
|
-
marimo_files = list(downloads_dir.rglob('
|
|
493
|
+
marimo_files = list(downloads_dir.rglob('*_marimo.py'))
|
|
498
494
|
python_files = [p for p in downloads_dir.rglob('*.py') if p not in marimo_files]
|
|
499
495
|
jupyter_files = list(downloads_dir.rglob('*.ipynb'))
|
|
500
496
|
|
|
@@ -520,11 +516,7 @@ def test_base_url_unset_no_links_anywhere(
|
|
|
520
516
|
python_src = _read(built[1], 'case_regular_xref_for_base_url')
|
|
521
517
|
assert 'http' not in python_src
|
|
522
518
|
|
|
523
|
-
nb_path = next(
|
|
524
|
-
p
|
|
525
|
-
for p in built_jupyter_notebooks
|
|
526
|
-
if p.stem == 'docstring_cases_case_regular_xref_for_base_url'
|
|
527
|
-
)
|
|
519
|
+
nb_path = next(p for p in built_jupyter_notebooks if p.stem == 'case_regular_xref_for_base_url')
|
|
528
520
|
nb_text = nb_path.read_text(encoding='utf-8')
|
|
529
521
|
assert 'http' not in nb_text
|
|
530
522
|
assert '](' not in nb_text # no markdown links
|
|
@@ -553,7 +545,7 @@ def test_base_url_set_resolves_links(tmp_path: Path):
|
|
|
553
545
|
assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
|
|
554
546
|
|
|
555
547
|
downloads_dir = html_dir / '_downloads'
|
|
556
|
-
python_files = [p for p in downloads_dir.rglob('*.py') if not p.name.endswith('.
|
|
548
|
+
python_files = [p for p in downloads_dir.rglob('*.py') if not p.name.endswith('_marimo.py')]
|
|
557
549
|
jupyter_files = list(downloads_dir.rglob('*.ipynb'))
|
|
558
550
|
|
|
559
551
|
# a regular reference: link resolved in .ipynb, omitted in .py
|
|
@@ -562,7 +554,7 @@ def test_base_url_set_resolves_links(tmp_path: Path):
|
|
|
562
554
|
assert '`docstring_cases.Sample`' in regular_python
|
|
563
555
|
|
|
564
556
|
regular_nb = next(
|
|
565
|
-
p for p in jupyter_files if p.stem == '
|
|
557
|
+
p for p in jupyter_files if p.stem == 'case_regular_xref_for_base_url'
|
|
566
558
|
).read_text(encoding='utf-8')
|
|
567
559
|
assert '[`docstring_cases.Sample`](https://docs.example.com/' in regular_nb
|
|
568
560
|
|
|
@@ -601,7 +593,7 @@ def test_markdown_cells_use_hard_line_breaks(built_jupyter_notebooks: list[Path]
|
|
|
601
593
|
with no blank line between -- not the header cell, which is a single
|
|
602
594
|
ATX heading line with nothing else to connect to.
|
|
603
595
|
"""
|
|
604
|
-
nb_path = next(p for p in built_jupyter_notebooks if p.stem == '
|
|
596
|
+
nb_path = next(p for p in built_jupyter_notebooks if p.stem == 'case_note')
|
|
605
597
|
notebook = json.loads(nb_path.read_text(encoding='utf-8'))
|
|
606
598
|
note_cell = next(
|
|
607
599
|
c
|
|
@@ -632,9 +624,7 @@ def test_html_baseurl_missing_scheme_disables_links_without_failing_build(tmp_pa
|
|
|
632
624
|
)
|
|
633
625
|
assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
|
|
634
626
|
|
|
635
|
-
nb_path = next(
|
|
636
|
-
(html_dir / '_downloads').rglob('docstring_cases_case_regular_xref_for_base_url.ipynb')
|
|
637
|
-
)
|
|
627
|
+
nb_path = next((html_dir / '_downloads').rglob('case_regular_xref_for_base_url.ipynb'))
|
|
638
628
|
nb_text = nb_path.read_text(encoding='utf-8')
|
|
639
629
|
assert '](' not in nb_text # no markdown links -- same as html_baseurl unset entirely
|
|
640
630
|
|
|
@@ -653,9 +643,7 @@ def test_base_url_missing_trailing_slash_still_resolves_subpath(tmp_path: Path):
|
|
|
653
643
|
)
|
|
654
644
|
assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
|
|
655
645
|
|
|
656
|
-
nb_path = next(
|
|
657
|
-
(html_dir / '_downloads').rglob('docstring_cases_case_regular_xref_for_base_url.ipynb')
|
|
658
|
-
)
|
|
646
|
+
nb_path = next((html_dir / '_downloads').rglob('case_regular_xref_for_base_url.ipynb'))
|
|
659
647
|
nb_text = nb_path.read_text(encoding='utf-8')
|
|
660
648
|
assert 'https://docs.example.com/en/stable/docstring_cases.html' in nb_text
|
|
661
649
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/gallery_fixture/conf.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/gallery_fixture/index.rst
RENAMED
|
File without changes
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/heading_level_fixture/conf.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/test_heading_level_reuse.py
RENAMED
|
File without changes
|
|
File without changes
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/tinypages/docstring_cases.py
RENAMED
|
File without changes
|
{sphinx_examples_as_code-0.8.0 → sphinx_examples_as_code-0.8.2}/tests/tinypages/docstring_cases.rst
RENAMED
|
File without changes
|
|
File without changes
|