Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5ce6866

Browse filesBrowse files
committed
minigallery generated from files and glob
1 parent a49a663 commit 5ce6866
Copy full SHA for 5ce6866

File tree

Expand file treeCollapse file tree

7 files changed

+215
-72
lines changed
Filter options
Expand file treeCollapse file tree

7 files changed

+215
-72
lines changed

‎dev-requirements.txt

Copy file name to clipboardExpand all lines: dev-requirements.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ absl-py
1212
graphviz
1313
packaging
1414
jupyterlite-sphinx
15+
lxml

‎doc/configuration.rst

Copy file name to clipboardExpand all lines: doc/configuration.rst
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,21 @@ examples into a single mini-gallery, e.g.:
598598
For such a mini-gallery, specifying a custom heading message is recommended
599599
because the default message is vague: "Examples of one of multiple objects".
600600

601+
Create mini-galleries using filepaths
602+
"""""""""""""""""""""""""""""""""""""
603+
Sometimes you may want to explicitly create a mini-gallery for files that may be
604+
in the same location but not have functions in common, for example a set of
605+
tutorials. The mini-gallery directive supports passing in a string path and
606+
a glob-style string to a set of files.
607+
608+
.. code-block:: rst
609+
610+
.. minigallery:: numpy.exp ../examples/plot_0_sin.py ../examples/plot_4*
611+
612+
613+
.. minigallery:: numpy.exp ../examples/plot_0_sin.py ../examples/plot_4*
614+
:add-heading: Mini-gallery using paths
615+
601616
Auto-documenting your API with links to examples
602617
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
603618

‎sphinx_gallery/backreferences.py

Copy file name to clipboardExpand all lines: sphinx_gallery/backreferences.py
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@
2727
2828
<div class="sphx-glr-thumbnails">
2929
30+
.. thumbnail-parent-div-open
3031
"""
3132

3233
THUMBNAIL_PARENT_DIV_CLOSE = """
34+
.. thumbnail-parent-div-close
35+
3336
.. raw:: html
3437
3538
</div>

‎sphinx_gallery/directives.py

Copy file name to clipboardExpand all lines: sphinx_gallery/directives.py
+60-24Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Custom Sphinx directives."""
2+
import glob
23
import os
34
from pathlib import PurePosixPath
45
import shutil
@@ -11,11 +12,26 @@
1112
from sphinx.errors import ExtensionError
1213

1314

15+
from .backreferences import (
16+
_thumbnail_div,
17+
THUMBNAIL_PARENT_DIV,
18+
THUMBNAIL_PARENT_DIV_CLOSE,
19+
)
20+
from .gen_rst import extract_intro_and_title
21+
from .py_source_parser import split_code_and_text_blocks
22+
23+
1424
class MiniGallery(Directive):
1525
"""Custom directive to insert a mini-gallery.
1626
17-
The required argument is one or more fully qualified names of objects,
18-
separated by spaces. The mini-gallery will be the subset of gallery
27+
The required argument is a one or more of the following:
28+
* fully qualified names of objects
29+
* pathlike strings to example Python files
30+
* glob-style pathlike strings to example Python files
31+
32+
The string list of arguments is separated by spaces.
33+
34+
The mini-gallery will be the subset of gallery
1935
examples that make use of that object (from that specific namespace).
2036
2137
Options:
@@ -47,11 +63,10 @@ def run(self):
4763
# Retrieve the backreferences directory
4864
config = self.state.document.settings.env.config
4965
backreferences_dir = config.sphinx_gallery_conf["backreferences_dir"]
50-
5166
# Parse the argument into the individual objects
5267
obj_list = self.arguments[0].split()
5368

54-
lines = []
69+
lines = [THUMBNAIL_PARENT_DIV]
5570

5671
# Add a heading if requested
5772
if "add-heading" in self.options:
@@ -65,32 +80,53 @@ def run(self):
6580
heading_level = self.options.get("heading-level", "^")
6681
lines.append(heading_level * len(heading))
6782

68-
def has_backrefs(obj):
69-
src_dir = config.sphinx_gallery_conf["src_dir"]
83+
src_dir = config.sphinx_gallery_conf["src_dir"]
84+
85+
def get_backrefs(obj):
7086
path = os.path.join(src_dir, backreferences_dir, f"{obj}.examples")
71-
return os.path.isfile(path) and os.path.getsize(path) > 0
87+
return (
88+
path if (os.path.isfile(path) and os.path.getsize(path) > 0) else False
89+
)
7290

73-
if not any(has_backrefs(obj) for obj in obj_list):
74-
return []
91+
example_dirs = [
92+
os.path.normpath(os.path.join(src_dir, edir))
93+
for edir in config.sphinx_gallery_conf["examples_dirs"]
94+
]
95+
gallery_dirs = config.sphinx_gallery_conf["gallery_dirs"]
7596

76-
# Insert the backreferences file(s) using the `include` directive.
77-
# This already includes the opening <div class="sphx-glr-thumbnails">
78-
# and its closing </div>.
7997
for obj in obj_list:
80-
path = os.path.join(
81-
"/", # Sphinx treats this as the source dir
82-
backreferences_dir,
83-
f"{obj}.examples",
84-
)
85-
86-
# Always remove the heading from the file
87-
lines.append(
88-
f"""\
98+
if paths := glob.glob(path := os.path.normpath(os.path.join(src_dir, obj))):
99+
# index of example dir that matches one of the dirs in path
100+
ix = [i for i, e in enumerate(example_dirs) if path.startswith(e)]
101+
target_dir = os.path.normpath(
102+
os.path.join(src_dir, gallery_dirs[ix[0]])
103+
)
104+
105+
for p in paths:
106+
# figure out what's causing animation to be weird here
107+
_, script_blocks = split_code_and_text_blocks(p, return_node=False)
108+
intro, title = extract_intro_and_title(p, script_blocks[0][1])
109+
# find the gallery dir that corresponds to the example dir
110+
111+
thumbnail = _thumbnail_div(
112+
target_dir, src_dir, p.split(os.sep)[-1], intro, title
113+
)
114+
lines.append(thumbnail)
115+
elif path := get_backrefs(obj):
116+
# Insert the backreferences file(s) using the `include` directive.
117+
# This already includes the opening <div class="sphx-glr-thumbnails">
118+
# and its closing </div>.
119+
120+
lines.append(
121+
f"""\
89122
.. include:: {path}
90-
:start-after: start-sphx-glr-thumbnails"""
91-
)
123+
:start-after: thumbnail-parent-div-open
124+
:end-before: thumbnail-parent-div-close"""
125+
)
126+
else:
127+
path = ""
92128

93-
# Parse the assembly of `include` and `raw` directives
129+
lines.append(THUMBNAIL_PARENT_DIV_CLOSE)
94130
text = "\n".join(lines)
95131
include_lines = statemachine.string2lines(text, convert_whitespace=True)
96132
self.state_machine.insert_input(include_lines, path)

‎sphinx_gallery/tests/test_full.py

Copy file name to clipboardExpand all lines: sphinx_gallery/tests/test_full.py
+68-48Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import glob
1515
import json
1616

17+
import lxml.html
1718
from packaging.version import Version
1819

1920
from sphinx import __version__ as sphinx_version
@@ -1069,69 +1070,88 @@ def test_backreference_labels(sphinx_app):
10691070
assert link in html
10701071

10711072

1073+
@pytest.fixture(scope="module")
1074+
def minigallery_tree(sphinx_app):
1075+
out_dir = sphinx_app.outdir
1076+
minigallery_html = op.join(out_dir, "minigallery.html")
1077+
with codecs.open(minigallery_html, "r", "utf-8") as fid:
1078+
tree = lxml.html.fromstring(fid.read())
1079+
return tree
1080+
1081+
10721082
@pytest.mark.parametrize(
1073-
"test, nlines, filenamesortkey",
1083+
"test, heading, sortkey",
10741084
[
10751085
# first example, no heading
1076-
("Test 1-N", 5, False),
1086+
("Test 1-N", None, {"explicit"}),
10771087
# first example, default heading, default level
1078-
("Test 1-D-D", 7, False),
1088+
("Test 1-D-D", ("h3", "Examples using", "ExplicitOrder"), {"explicit"}),
10791089
# first example, default heading, custom level
1080-
("Test 1-D-C", 7, False),
1090+
("Test 1-D-C", ("h2", "Examples using", "ExplicitOrder"), {"explicit"}),
10811091
# first example, custom heading, default level
1082-
("Test 1-C-D", 8, False),
1092+
("Test 1-C-D", ("h3", "This is a custom heading", ""), {"explicit"}),
10831093
# both examples, no heading
1084-
("Test 2-N", 10, True),
1094+
("Test 2-N", None, {"explicit", "filename"}),
10851095
# both examples, default heading, default level
1086-
("Test 2-D-D", 13, True),
1096+
(
1097+
"Test 2-D-D",
1098+
("h3", "Examples using one of multiple objects", ""),
1099+
{"explicit", "filename"},
1100+
),
10871101
# both examples, custom heading, custom level
1088-
("Test 2-C-C", 14, True),
1102+
(
1103+
"Test 2-C-C",
1104+
("h1", "This is a different custom heading", ""),
1105+
{"explicit", "filename"},
1106+
),
1107+
# filepath, no heading
1108+
("Test 1-F", None, {"path"}),
1109+
# glob, no heading
1110+
("Test 2-F-G", None, {"glob"}),
1111+
# all files
1112+
(
1113+
"Test 3-F-G-B",
1114+
("h3", "All the input types", ""),
1115+
{"path", "glob", "explicit", "filename"},
1116+
),
10891117
],
10901118
)
1091-
def test_minigallery_directive(sphinx_app, test, nlines, filenamesortkey):
1119+
def test_minigallery_directive(minigallery_tree, test, heading, sortkey):
10921120
"""Tests the functionality of the minigallery directive."""
1093-
out_dir = sphinx_app.outdir
1094-
minigallery_html = op.join(out_dir, "minigallery.html")
1095-
with codecs.open(minigallery_html, "r", "utf-8") as fid:
1096-
lines = fid.readlines()
1121+
text = minigallery_tree.get_element_by_id(test.lower().replace(" ", "-")).xpath(
1122+
'div[@class="sphx-glr-thumbnails"]'
1123+
)[0]
1124+
# Check headings
1125+
if heading:
1126+
assert text.xpath(
1127+
'descendant::{}[starts-with(text(), "{}") and contains(.,"{}")]'.format(
1128+
*heading
1129+
)
1130+
)
1131+
else:
1132+
assert text.xpath('descendant::*[starts-with(name(), "h")]') == []
10971133

1098-
# Regular expressions for matching
1099-
any_heading = re.compile(r"<h([1-6])>.+<\/h\1>")
1100-
explicitorder_example = re.compile(
1101-
r"(?s)<img .+" r"(plot_second_future_imports).+" r"auto_examples\/\1\.html"
1102-
)
1103-
filenamesortkey_example = re.compile(
1104-
r"(?s)<img .+" r"(plot_numpy_matplotlib).+" r"auto_examples\/\1\.html"
1105-
)
1106-
# Heading strings
1107-
heading_str = {
1108-
"Test 1-N": None,
1109-
"Test 1-D-D": r"<h2>Examples using .+ExplicitOrder.+<\/h2>",
1110-
"Test 1-D-C": r"<h3>Examples using .+ExplicitOrder.+<\/h3>",
1111-
"Test 1-C-D": r"<h2>This is a custom heading.*<\/h2>",
1112-
"Test 2-N": None,
1113-
"Test 2-D-D": r"<h2>Examples using one of multiple objects.*<\/h2>",
1114-
"Test 2-C-C": r"<h1>This is a different custom heading.*<\/h1>",
1134+
examples = {
1135+
"explicit": "plot_second_future_imports",
1136+
"filename": "plot_numpy_matplotlib",
1137+
"path": "plot_log",
1138+
"glob": "plot_matplotlib_alt",
11151139
}
11161140

1117-
for i in range(len(lines)):
1118-
if test in lines[i]:
1119-
text = "".join(lines[i : i + nlines])
1120-
print(f"{test}: {text}")
1121-
# Check headings
1122-
if heading_str[test]:
1123-
heading = re.compile(heading_str[test])
1124-
assert heading.search(text) is not None
1125-
else:
1126-
# Confirm there isn't a heading
1127-
assert any_heading.search(text) is None
1128-
1129-
# Check for examples
1130-
assert explicitorder_example.search(text) is not None
1131-
if filenamesortkey:
1132-
assert filenamesortkey_example.search(text) is not None
1133-
else:
1134-
assert filenamesortkey_example.search(text) is None
1141+
for key, fname in examples.items():
1142+
img = text.xpath(
1143+
f'descendant::img[@src = "_images/sphx_glr_{fname}_thumb.png"]'
1144+
)
1145+
href = text.xpath(
1146+
f'descendant::a[starts-with(@href, "auto_examples/{fname}.html")]'
1147+
)
1148+
if key in sortkey:
1149+
assert img and href
1150+
1151+
else:
1152+
assert not (img or href)
1153+
1154+
print(f"{test}: {lxml.html.tostring(text)}")
11351155

11361156

11371157
def test_matplotlib_warning_filter(sphinx_app):
+45Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@ECHO OFF
2+
3+
REM Command file for Sphinx documentation
4+
5+
set SPHINXOPTS = -v
6+
7+
if "%SPHINXBUILD%" == "" (
8+
set SPHINXBUILD=sphinx-build
9+
)
10+
set BUILDDIR=_build
11+
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
12+
13+
if "%1" == "clean" (
14+
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
15+
del /q /s %BUILDDIR%\*
16+
if exist auto_examples rd /q /s auto_examples
17+
if exist auto_plotly_examples rd /q /s auto_plotly_examples
18+
if exist auto_pyvista_examples rd /q /s auto_pyvista_examples
19+
if exist tutorials rd /q /s tutorials
20+
if exist gen_modules rd /q /s gen_modules
21+
goto end
22+
)
23+
24+
25+
if "%1" == "html" (
26+
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
27+
if errorlevel 1 exit /b 1
28+
echo.
29+
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
30+
goto end
31+
)
32+
33+
34+
if "%1" == "latexpdf" (
35+
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
36+
cd %BUILDDIR%/latex
37+
make all-pdf
38+
cd %BUILDDIR%/..
39+
echo.
40+
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
41+
goto end
42+
)
43+
44+
45+
:end

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.