zallery 0.0.1__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.
- zallery-0.0.1/LICENSE +27 -0
- zallery-0.0.1/PKG-INFO +232 -0
- zallery-0.0.1/README.md +199 -0
- zallery-0.0.1/pyproject.toml +101 -0
- zallery-0.0.1/pyproject.toml.orig +98 -0
- zallery-0.0.1/src/zallery/__init__.py +11 -0
- zallery-0.0.1/src/zallery/__main__.py +5 -0
- zallery-0.0.1/src/zallery/_types.py +43 -0
- zallery-0.0.1/src/zallery/cache.py +58 -0
- zallery-0.0.1/src/zallery/cli.py +96 -0
- zallery-0.0.1/src/zallery/config.py +204 -0
- zallery-0.0.1/src/zallery/discover.py +54 -0
- zallery-0.0.1/src/zallery/execute.py +245 -0
- zallery-0.0.1/src/zallery/index.py +155 -0
- zallery-0.0.1/src/zallery/pipeline.py +418 -0
- zallery-0.0.1/src/zallery/py.typed +0 -0
- zallery-0.0.1/src/zallery/render.py +405 -0
- zallery-0.0.1/src/zallery/theme.py +274 -0
zallery-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026, The ConfUSIus developers
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without modification, are
|
|
6
|
+
permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this list of
|
|
9
|
+
conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
12
|
+
of conditions and the following disclaimer in the documentation and/or other
|
|
13
|
+
materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
16
|
+
used to endorse or promote products derived from this software without specific prior
|
|
17
|
+
written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY
|
|
20
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
21
|
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
22
|
+
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
23
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
24
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
25
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
26
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
zallery-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zallery
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Build a light-and-dark example gallery for Zensical docs from jupytext scripts.
|
|
5
|
+
Author: ConfUSIus developers
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Documentation
|
|
17
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Dist: ipykernel>=6.29.0
|
|
20
|
+
Requires-Dist: ipython>=9.6.0
|
|
21
|
+
Requires-Dist: jupyter-client>=8.6.0
|
|
22
|
+
Requires-Dist: jupytext>=1.16.0
|
|
23
|
+
Requires-Dist: matplotlib>=3.11.0
|
|
24
|
+
Requires-Dist: matplotlib-inline>=0.1.7
|
|
25
|
+
Requires-Dist: nbclient>=0.10.0
|
|
26
|
+
Requires-Dist: nbformat>=5.10.0
|
|
27
|
+
Requires-Dist: numpy>=2.3.4
|
|
28
|
+
Requires-Dist: rich>=14.2.0
|
|
29
|
+
Requires-Python: >=3.11, <3.15
|
|
30
|
+
Project-URL: Repository, https://github.com/confusius-tools/zallery
|
|
31
|
+
Project-URL: Issues, https://github.com/confusius-tools/zallery/issues
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/zallery/)
|
|
35
|
+
[](https://pypi.org/project/zallery/)
|
|
36
|
+
[](https://github.com/confusius-tools/zallery/blob/main/LICENSE)
|
|
37
|
+
|
|
38
|
+
# zallery
|
|
39
|
+
|
|
40
|
+
**zallery** builds an example gallery for [Zensical](https://zensical.org)
|
|
41
|
+
documentation sites from plain Python scripts.
|
|
42
|
+
|
|
43
|
+
Each example is a [jupytext](https://jupytext.readthedocs.io) percent-format `.py`
|
|
44
|
+
file. zallery runs it once in a Jupyter kernel, renders it as a notebook-style
|
|
45
|
+
Markdown page with code, outputs, and `.py`/`.ipynb` downloads, and writes an index
|
|
46
|
+
page with one card per example. Every matplotlib figure comes out twice, for the
|
|
47
|
+
light and the dark color scheme, from that single run.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv add --dev zallery
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or with pip:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install zallery
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
Add a `[tool.zallery]` table to the project's `pyproject.toml` (an empty table is
|
|
64
|
+
enough, every key has a default):
|
|
65
|
+
|
|
66
|
+
```toml
|
|
67
|
+
[tool.zallery]
|
|
68
|
+
examples = "docs/examples"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Create a section with one example:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
mkdir -p docs/examples/my-section
|
|
75
|
+
printf '# My section\n\nIntro.\n' > docs/examples/my-section/_section.md
|
|
76
|
+
cat > docs/examples/my-section/hello.py <<'EOF'
|
|
77
|
+
# %% [markdown]
|
|
78
|
+
# # My example
|
|
79
|
+
#
|
|
80
|
+
# Short description.
|
|
81
|
+
|
|
82
|
+
# %%
|
|
83
|
+
print("hi")
|
|
84
|
+
EOF
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Build the gallery from anywhere inside the project:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv run zallery
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This writes `docs/examples/index.md` (the card index) and
|
|
94
|
+
`docs/examples/_built/my-section/hello.md` with its images and downloads. Add them
|
|
95
|
+
to the site navigation like any other page; both are generated, so keep them and
|
|
96
|
+
the cache directory out of version control.
|
|
97
|
+
|
|
98
|
+
## Command line
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
zallery [--no-run] [--no-cache] [EXAMPLE ...]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- With no arguments, every example is executed, or restored from cache when its
|
|
105
|
+
source and the cache fingerprint are unchanged.
|
|
106
|
+
- Name example scripts to run only those. The whole gallery is still rendered: the
|
|
107
|
+
others are restored from cache if present, or rendered with code and Markdown only.
|
|
108
|
+
- `--no-run` executes nothing, to iterate on prose or layout.
|
|
109
|
+
- `--no-cache` executes the selected examples even when a cached result exists; the
|
|
110
|
+
result replaces the cache entry.
|
|
111
|
+
|
|
112
|
+
`python -m zallery` is equivalent.
|
|
113
|
+
|
|
114
|
+
## Writing examples
|
|
115
|
+
|
|
116
|
+
Examples live under `<examples>/<section>/<name>.py`.
|
|
117
|
+
|
|
118
|
+
- The first Markdown heading of an example is its page title; the next Markdown
|
|
119
|
+
paragraph is the summary shown on its index card.
|
|
120
|
+
- A section folder may contain a `_section.md` whose first heading becomes the section
|
|
121
|
+
title on the index page.
|
|
122
|
+
- An `_index.md` in the examples root replaces the default header of the index page.
|
|
123
|
+
- A leading numeric prefix (`01_io/`, `02_first.py`) orders sections and examples and
|
|
124
|
+
is stripped from the built names.
|
|
125
|
+
- Files and folders starting with `_` are skipped.
|
|
126
|
+
- Tag a cell with `thumbnail` to use its first image output on the index card.
|
|
127
|
+
- Tag a cell with `collapse` (or `collapse: <title>`) to hide its code behind a
|
|
128
|
+
collapsed callout, handy for setup the reader can expand on demand. The cell still
|
|
129
|
+
runs, and its output renders normally below the callout. The callout defaults to the
|
|
130
|
+
`example` admonition; pick another type with `collapse[<type>]` or
|
|
131
|
+
`collapse[<type>]: <title>`, where `<type>` is any
|
|
132
|
+
[admonition](https://zensical.org/docs/authoring/admonitions/) name Zensical
|
|
133
|
+
understands (`warning`, `tip`, `note`, ...).
|
|
134
|
+
- A failing cell does not abort the build: its traceback is rendered on the page.
|
|
135
|
+
|
|
136
|
+
## Light and dark figures
|
|
137
|
+
|
|
138
|
+
Every example runs once, under a light matplotlib style. Each figure is then
|
|
139
|
+
re-rendered for dark mode without re-executing anything: zallery swaps the theme
|
|
140
|
+
colors (figure background, axes background, black foreground) and the default
|
|
141
|
+
diverging colormap (`coolwarm` to `berlin`) on the drawn artists, prints a second
|
|
142
|
+
PNG, and swaps everything back. Both PNGs land on the page, and the site shows the
|
|
143
|
+
one matching the reader's color scheme.
|
|
144
|
+
|
|
145
|
+
What this means when writing an example:
|
|
146
|
+
|
|
147
|
+
- Read backgrounds from matplotlib rather than hardcoding them, for example
|
|
148
|
+
`mpl.rcParams["figure.facecolor"]`. Pure black and pure white are theme colors
|
|
149
|
+
wherever they appear (text, lines, line markers, and backgrounds). Per-element
|
|
150
|
+
colors (`scatter(c="black")`, collections) are left alone, and any other explicit
|
|
151
|
+
color is kept as is.
|
|
152
|
+
- Do not branch on the theme in the example: there is only one run. Pick colormaps
|
|
153
|
+
that read well on both backgrounds, or swap them with a hook (below).
|
|
154
|
+
- Images not drawn by matplotlib (PIL images, screenshots) are shown unchanged in
|
|
155
|
+
both themes.
|
|
156
|
+
|
|
157
|
+
When the built-in swap is not enough, point the `hook` key at a module of the
|
|
158
|
+
project that defines `gallery_retheme(fig, theme)`. It runs in the kernel after the
|
|
159
|
+
swap, with `"dark"` before the dark rendering and `"light"` after the figure is
|
|
160
|
+
swapped back, and must undo for `"light"` what it did for `"dark"`:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from zallery.theme import swap_cmaps
|
|
164
|
+
|
|
165
|
+
SWAPS = {"inferno_r": "inferno"}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def gallery_retheme(fig, theme):
|
|
169
|
+
"""Draw with `inferno_r` on the light page, `inferno` on the dark page."""
|
|
170
|
+
mapping = SWAPS if theme == "dark" else {dark: light for light, dark in SWAPS.items()}
|
|
171
|
+
swap_cmaps(fig, mapping)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Configuration
|
|
175
|
+
|
|
176
|
+
zallery reads the `[tool.zallery]` table of the nearest `pyproject.toml` above the
|
|
177
|
+
working directory; relative paths resolve against that file's directory. All keys
|
|
178
|
+
are optional:
|
|
179
|
+
|
|
180
|
+
| Key | Default | Meaning |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `examples` | `docs/examples` | Directory of example sections. |
|
|
183
|
+
| `built` | `<examples>/_built` | Where rendered pages and images go. |
|
|
184
|
+
| `cache` | `.gallery-cache` | Execution/render cache. |
|
|
185
|
+
| `binder_repo` | unset | `owner/repo` for the Binder launch buttons. |
|
|
186
|
+
| `hook` | unset | Dotted name of a module, importable from the project root, defining `gallery_retheme(fig, theme)`. |
|
|
187
|
+
| `fingerprint` | `["uv.lock"]` | Files whose change invalidates the cache. |
|
|
188
|
+
|
|
189
|
+
The git ref stamped into Binder URLs comes from the `ZALLERY_BINDER_REF`
|
|
190
|
+
environment variable (default `main`).
|
|
191
|
+
|
|
192
|
+
A cached example is reused while its source, the Python version, the configuration,
|
|
193
|
+
the `fingerprint` files, the hook module, and the zallery sources are all unchanged.
|
|
194
|
+
|
|
195
|
+
## Site integration
|
|
196
|
+
|
|
197
|
+
zallery writes Markdown; the site provides the rest:
|
|
198
|
+
|
|
199
|
+
- Markdown extensions `attr_list`, `md_in_html`, `admonition`, `pymdownx.details`
|
|
200
|
+
and `pymdownx.superfences`.
|
|
201
|
+
- Two CSS rules so each image shows in its own color scheme:
|
|
202
|
+
|
|
203
|
+
```css
|
|
204
|
+
[data-md-color-scheme="slate"] img[src$="#only-light"] { display: none; }
|
|
205
|
+
[data-md-color-scheme="default"] img[src$="#only-dark"] { display: none; }
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- Fallback thumbnails for examples without a `thumbnail` cell, at
|
|
209
|
+
`<examples>/_assets/default_thumb.svg` and `<examples>/_assets/default_thumb_dark.svg`.
|
|
210
|
+
- Optionally, styles for the classes zallery emits: `examples-cards` and
|
|
211
|
+
`examples-card-summary` on the index page, `gallery-output` and
|
|
212
|
+
`gallery-rich-output` around cell outputs. The
|
|
213
|
+
[ConfUSIus stylesheet](https://github.com/confusius-tools/confusius/blob/main/docs/stylesheets/extra.css)
|
|
214
|
+
is a complete example.
|
|
215
|
+
|
|
216
|
+
## Relationship to ConfUSIus
|
|
217
|
+
|
|
218
|
+
zallery is extracted from [ConfUSIus](https://github.com/confusius-tools/confusius),
|
|
219
|
+
where it builds the documentation's example gallery. It does not depend on
|
|
220
|
+
ConfUSIus and makes no assumption about what the examples compute.
|
|
221
|
+
|
|
222
|
+
## Development
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
uv sync # install dependencies
|
|
226
|
+
just test # run tests
|
|
227
|
+
just pre-commit # run lint, format, type checks, docstring checks
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
BSD-3-Clause. See `LICENSE`.
|
zallery-0.0.1/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
[](https://pypi.org/project/zallery/)
|
|
2
|
+
[](https://pypi.org/project/zallery/)
|
|
3
|
+
[](https://github.com/confusius-tools/zallery/blob/main/LICENSE)
|
|
4
|
+
|
|
5
|
+
# zallery
|
|
6
|
+
|
|
7
|
+
**zallery** builds an example gallery for [Zensical](https://zensical.org)
|
|
8
|
+
documentation sites from plain Python scripts.
|
|
9
|
+
|
|
10
|
+
Each example is a [jupytext](https://jupytext.readthedocs.io) percent-format `.py`
|
|
11
|
+
file. zallery runs it once in a Jupyter kernel, renders it as a notebook-style
|
|
12
|
+
Markdown page with code, outputs, and `.py`/`.ipynb` downloads, and writes an index
|
|
13
|
+
page with one card per example. Every matplotlib figure comes out twice, for the
|
|
14
|
+
light and the dark color scheme, from that single run.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv add --dev zallery
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or with pip:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install zallery
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
Add a `[tool.zallery]` table to the project's `pyproject.toml` (an empty table is
|
|
31
|
+
enough, every key has a default):
|
|
32
|
+
|
|
33
|
+
```toml
|
|
34
|
+
[tool.zallery]
|
|
35
|
+
examples = "docs/examples"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Create a section with one example:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
mkdir -p docs/examples/my-section
|
|
42
|
+
printf '# My section\n\nIntro.\n' > docs/examples/my-section/_section.md
|
|
43
|
+
cat > docs/examples/my-section/hello.py <<'EOF'
|
|
44
|
+
# %% [markdown]
|
|
45
|
+
# # My example
|
|
46
|
+
#
|
|
47
|
+
# Short description.
|
|
48
|
+
|
|
49
|
+
# %%
|
|
50
|
+
print("hi")
|
|
51
|
+
EOF
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Build the gallery from anywhere inside the project:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
uv run zallery
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This writes `docs/examples/index.md` (the card index) and
|
|
61
|
+
`docs/examples/_built/my-section/hello.md` with its images and downloads. Add them
|
|
62
|
+
to the site navigation like any other page; both are generated, so keep them and
|
|
63
|
+
the cache directory out of version control.
|
|
64
|
+
|
|
65
|
+
## Command line
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
zallery [--no-run] [--no-cache] [EXAMPLE ...]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- With no arguments, every example is executed, or restored from cache when its
|
|
72
|
+
source and the cache fingerprint are unchanged.
|
|
73
|
+
- Name example scripts to run only those. The whole gallery is still rendered: the
|
|
74
|
+
others are restored from cache if present, or rendered with code and Markdown only.
|
|
75
|
+
- `--no-run` executes nothing, to iterate on prose or layout.
|
|
76
|
+
- `--no-cache` executes the selected examples even when a cached result exists; the
|
|
77
|
+
result replaces the cache entry.
|
|
78
|
+
|
|
79
|
+
`python -m zallery` is equivalent.
|
|
80
|
+
|
|
81
|
+
## Writing examples
|
|
82
|
+
|
|
83
|
+
Examples live under `<examples>/<section>/<name>.py`.
|
|
84
|
+
|
|
85
|
+
- The first Markdown heading of an example is its page title; the next Markdown
|
|
86
|
+
paragraph is the summary shown on its index card.
|
|
87
|
+
- A section folder may contain a `_section.md` whose first heading becomes the section
|
|
88
|
+
title on the index page.
|
|
89
|
+
- An `_index.md` in the examples root replaces the default header of the index page.
|
|
90
|
+
- A leading numeric prefix (`01_io/`, `02_first.py`) orders sections and examples and
|
|
91
|
+
is stripped from the built names.
|
|
92
|
+
- Files and folders starting with `_` are skipped.
|
|
93
|
+
- Tag a cell with `thumbnail` to use its first image output on the index card.
|
|
94
|
+
- Tag a cell with `collapse` (or `collapse: <title>`) to hide its code behind a
|
|
95
|
+
collapsed callout, handy for setup the reader can expand on demand. The cell still
|
|
96
|
+
runs, and its output renders normally below the callout. The callout defaults to the
|
|
97
|
+
`example` admonition; pick another type with `collapse[<type>]` or
|
|
98
|
+
`collapse[<type>]: <title>`, where `<type>` is any
|
|
99
|
+
[admonition](https://zensical.org/docs/authoring/admonitions/) name Zensical
|
|
100
|
+
understands (`warning`, `tip`, `note`, ...).
|
|
101
|
+
- A failing cell does not abort the build: its traceback is rendered on the page.
|
|
102
|
+
|
|
103
|
+
## Light and dark figures
|
|
104
|
+
|
|
105
|
+
Every example runs once, under a light matplotlib style. Each figure is then
|
|
106
|
+
re-rendered for dark mode without re-executing anything: zallery swaps the theme
|
|
107
|
+
colors (figure background, axes background, black foreground) and the default
|
|
108
|
+
diverging colormap (`coolwarm` to `berlin`) on the drawn artists, prints a second
|
|
109
|
+
PNG, and swaps everything back. Both PNGs land on the page, and the site shows the
|
|
110
|
+
one matching the reader's color scheme.
|
|
111
|
+
|
|
112
|
+
What this means when writing an example:
|
|
113
|
+
|
|
114
|
+
- Read backgrounds from matplotlib rather than hardcoding them, for example
|
|
115
|
+
`mpl.rcParams["figure.facecolor"]`. Pure black and pure white are theme colors
|
|
116
|
+
wherever they appear (text, lines, line markers, and backgrounds). Per-element
|
|
117
|
+
colors (`scatter(c="black")`, collections) are left alone, and any other explicit
|
|
118
|
+
color is kept as is.
|
|
119
|
+
- Do not branch on the theme in the example: there is only one run. Pick colormaps
|
|
120
|
+
that read well on both backgrounds, or swap them with a hook (below).
|
|
121
|
+
- Images not drawn by matplotlib (PIL images, screenshots) are shown unchanged in
|
|
122
|
+
both themes.
|
|
123
|
+
|
|
124
|
+
When the built-in swap is not enough, point the `hook` key at a module of the
|
|
125
|
+
project that defines `gallery_retheme(fig, theme)`. It runs in the kernel after the
|
|
126
|
+
swap, with `"dark"` before the dark rendering and `"light"` after the figure is
|
|
127
|
+
swapped back, and must undo for `"light"` what it did for `"dark"`:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from zallery.theme import swap_cmaps
|
|
131
|
+
|
|
132
|
+
SWAPS = {"inferno_r": "inferno"}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def gallery_retheme(fig, theme):
|
|
136
|
+
"""Draw with `inferno_r` on the light page, `inferno` on the dark page."""
|
|
137
|
+
mapping = SWAPS if theme == "dark" else {dark: light for light, dark in SWAPS.items()}
|
|
138
|
+
swap_cmaps(fig, mapping)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Configuration
|
|
142
|
+
|
|
143
|
+
zallery reads the `[tool.zallery]` table of the nearest `pyproject.toml` above the
|
|
144
|
+
working directory; relative paths resolve against that file's directory. All keys
|
|
145
|
+
are optional:
|
|
146
|
+
|
|
147
|
+
| Key | Default | Meaning |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| `examples` | `docs/examples` | Directory of example sections. |
|
|
150
|
+
| `built` | `<examples>/_built` | Where rendered pages and images go. |
|
|
151
|
+
| `cache` | `.gallery-cache` | Execution/render cache. |
|
|
152
|
+
| `binder_repo` | unset | `owner/repo` for the Binder launch buttons. |
|
|
153
|
+
| `hook` | unset | Dotted name of a module, importable from the project root, defining `gallery_retheme(fig, theme)`. |
|
|
154
|
+
| `fingerprint` | `["uv.lock"]` | Files whose change invalidates the cache. |
|
|
155
|
+
|
|
156
|
+
The git ref stamped into Binder URLs comes from the `ZALLERY_BINDER_REF`
|
|
157
|
+
environment variable (default `main`).
|
|
158
|
+
|
|
159
|
+
A cached example is reused while its source, the Python version, the configuration,
|
|
160
|
+
the `fingerprint` files, the hook module, and the zallery sources are all unchanged.
|
|
161
|
+
|
|
162
|
+
## Site integration
|
|
163
|
+
|
|
164
|
+
zallery writes Markdown; the site provides the rest:
|
|
165
|
+
|
|
166
|
+
- Markdown extensions `attr_list`, `md_in_html`, `admonition`, `pymdownx.details`
|
|
167
|
+
and `pymdownx.superfences`.
|
|
168
|
+
- Two CSS rules so each image shows in its own color scheme:
|
|
169
|
+
|
|
170
|
+
```css
|
|
171
|
+
[data-md-color-scheme="slate"] img[src$="#only-light"] { display: none; }
|
|
172
|
+
[data-md-color-scheme="default"] img[src$="#only-dark"] { display: none; }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- Fallback thumbnails for examples without a `thumbnail` cell, at
|
|
176
|
+
`<examples>/_assets/default_thumb.svg` and `<examples>/_assets/default_thumb_dark.svg`.
|
|
177
|
+
- Optionally, styles for the classes zallery emits: `examples-cards` and
|
|
178
|
+
`examples-card-summary` on the index page, `gallery-output` and
|
|
179
|
+
`gallery-rich-output` around cell outputs. The
|
|
180
|
+
[ConfUSIus stylesheet](https://github.com/confusius-tools/confusius/blob/main/docs/stylesheets/extra.css)
|
|
181
|
+
is a complete example.
|
|
182
|
+
|
|
183
|
+
## Relationship to ConfUSIus
|
|
184
|
+
|
|
185
|
+
zallery is extracted from [ConfUSIus](https://github.com/confusius-tools/confusius),
|
|
186
|
+
where it builds the documentation's example gallery. It does not depend on
|
|
187
|
+
ConfUSIus and makes no assumption about what the examples compute.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
uv sync # install dependencies
|
|
193
|
+
just test # run tests
|
|
194
|
+
just pre-commit # run lint, format, type checks, docstring checks
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
BSD-3-Clause. See `LICENSE`.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "zallery"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Build a light-and-dark example gallery for Zensical docs from jupytext scripts."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "BSD-3-Clause"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.11,<3.15"
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 3 - Alpha",
|
|
11
|
+
"Programming Language :: Python",
|
|
12
|
+
"Programming Language :: Python :: 3.11",
|
|
13
|
+
"Programming Language :: Python :: 3.12",
|
|
14
|
+
"Programming Language :: Python :: 3.13",
|
|
15
|
+
"Programming Language :: Python :: 3.14",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Topic :: Documentation",
|
|
19
|
+
"Topic :: Software Development :: Documentation",
|
|
20
|
+
"Typing :: Typed",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"ipykernel>=6.29.0",
|
|
24
|
+
"ipython>=9.6.0",
|
|
25
|
+
"jupyter-client>=8.6.0",
|
|
26
|
+
"jupytext>=1.16.0",
|
|
27
|
+
"matplotlib>=3.11.0",
|
|
28
|
+
"matplotlib-inline>=0.1.7",
|
|
29
|
+
"nbclient>=0.10.0",
|
|
30
|
+
"nbformat>=5.10.0",
|
|
31
|
+
"numpy>=2.3.4",
|
|
32
|
+
"rich>=14.2.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[project.authors]]
|
|
36
|
+
name = "ConfUSIus developers"
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Repository = "https://github.com/confusius-tools/zallery"
|
|
40
|
+
Issues = "https://github.com/confusius-tools/zallery/issues"
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
zallery = "zallery.cli:main"
|
|
44
|
+
|
|
45
|
+
[build-system]
|
|
46
|
+
requires = ["uv-build>=0.9.5,<0.14.0"]
|
|
47
|
+
build-backend = "uv_build"
|
|
48
|
+
|
|
49
|
+
[dependency-groups]
|
|
50
|
+
dev = [
|
|
51
|
+
"codespell>=2.3.0",
|
|
52
|
+
"numpydoc>=1.11.0",
|
|
53
|
+
"prek>=0.4.8",
|
|
54
|
+
"pytest>=9.1.1",
|
|
55
|
+
"pytest-cov>=6.0.0",
|
|
56
|
+
"ruff>=0.16.5",
|
|
57
|
+
"ty>=0.0.77,<0.1.0",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.numpydoc_validation]
|
|
61
|
+
exclude = [
|
|
62
|
+
'\.__init__$',
|
|
63
|
+
'\._.*$',
|
|
64
|
+
]
|
|
65
|
+
checks = [
|
|
66
|
+
"all",
|
|
67
|
+
"GL01",
|
|
68
|
+
"ES01",
|
|
69
|
+
"SA01",
|
|
70
|
+
"EX01",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.ruff]
|
|
74
|
+
line-length = 88
|
|
75
|
+
|
|
76
|
+
[tool.ty.src]
|
|
77
|
+
include = [
|
|
78
|
+
"src",
|
|
79
|
+
"tests",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[tool.pytest.ini_options]
|
|
83
|
+
minversion = "8.0"
|
|
84
|
+
testpaths = ["tests"]
|
|
85
|
+
pythonpath = ["."]
|
|
86
|
+
python_files = ["test_*.py"]
|
|
87
|
+
python_classes = ["Test*"]
|
|
88
|
+
python_functions = ["test_*"]
|
|
89
|
+
markers = ["slow: tests that start kernels."]
|
|
90
|
+
addopts = [
|
|
91
|
+
"-ra",
|
|
92
|
+
"--strict-markers",
|
|
93
|
+
"--strict-config",
|
|
94
|
+
"--import-mode=importlib",
|
|
95
|
+
"--showlocals",
|
|
96
|
+
"--cov=zallery",
|
|
97
|
+
"--cov-report=term-missing",
|
|
98
|
+
"--cov-report=html",
|
|
99
|
+
"--cov-report=xml",
|
|
100
|
+
]
|
|
101
|
+
filterwarnings = ["error"]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "zallery"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Build a light-and-dark example gallery for Zensical docs from jupytext scripts."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "BSD-3-Clause"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{ name = "ConfUSIus developers" }]
|
|
9
|
+
requires-python = ">=3.11,<3.15"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Programming Language :: Python",
|
|
13
|
+
"Programming Language :: Python :: 3.11",
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
"Programming Language :: Python :: 3.13",
|
|
16
|
+
"Programming Language :: Python :: 3.14",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Documentation",
|
|
20
|
+
"Topic :: Software Development :: Documentation",
|
|
21
|
+
"Typing :: Typed",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"ipykernel>=6.29.0",
|
|
25
|
+
"ipython>=9.6.0",
|
|
26
|
+
"jupyter-client>=8.6.0",
|
|
27
|
+
"jupytext>=1.16.0",
|
|
28
|
+
"matplotlib>=3.11.0",
|
|
29
|
+
"matplotlib-inline>=0.1.7",
|
|
30
|
+
"nbclient>=0.10.0",
|
|
31
|
+
"nbformat>=5.10.0",
|
|
32
|
+
"numpy>=2.3.4",
|
|
33
|
+
"rich>=14.2.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Repository = "https://github.com/confusius-tools/zallery"
|
|
38
|
+
Issues = "https://github.com/confusius-tools/zallery/issues"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
zallery = "zallery.cli:main"
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["uv-build>=0.9.5,<0.14.0"]
|
|
45
|
+
build-backend = "uv_build"
|
|
46
|
+
|
|
47
|
+
[dependency-groups]
|
|
48
|
+
dev = [
|
|
49
|
+
"codespell>=2.3.0",
|
|
50
|
+
"numpydoc>=1.11.0",
|
|
51
|
+
"prek>=0.4.8",
|
|
52
|
+
"pytest>=9.1.1",
|
|
53
|
+
"pytest-cov>=6.0.0",
|
|
54
|
+
"ruff>=0.16.5",
|
|
55
|
+
"ty>=0.0.77,<0.1.0",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.numpydoc_validation]
|
|
59
|
+
exclude = [
|
|
60
|
+
'\.__init__$',
|
|
61
|
+
'\._.*$',
|
|
62
|
+
]
|
|
63
|
+
checks = [
|
|
64
|
+
"all",
|
|
65
|
+
"GL01",
|
|
66
|
+
"ES01",
|
|
67
|
+
"SA01",
|
|
68
|
+
"EX01",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[tool.ruff]
|
|
72
|
+
line-length = 88
|
|
73
|
+
|
|
74
|
+
[tool.ty.src]
|
|
75
|
+
include = ["src", "tests"]
|
|
76
|
+
|
|
77
|
+
[tool.pytest.ini_options]
|
|
78
|
+
minversion = "8.0"
|
|
79
|
+
testpaths = ["tests"]
|
|
80
|
+
pythonpath = ["."]
|
|
81
|
+
python_files = ["test_*.py"]
|
|
82
|
+
python_classes = ["Test*"]
|
|
83
|
+
python_functions = ["test_*"]
|
|
84
|
+
markers = [
|
|
85
|
+
"slow: tests that start kernels.",
|
|
86
|
+
]
|
|
87
|
+
addopts = [
|
|
88
|
+
"-ra",
|
|
89
|
+
"--strict-markers",
|
|
90
|
+
"--strict-config",
|
|
91
|
+
"--import-mode=importlib",
|
|
92
|
+
"--showlocals",
|
|
93
|
+
"--cov=zallery",
|
|
94
|
+
"--cov-report=term-missing",
|
|
95
|
+
"--cov-report=html",
|
|
96
|
+
"--cov-report=xml",
|
|
97
|
+
]
|
|
98
|
+
filterwarnings = ["error"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Build a light-and-dark example gallery for Zensical docs from jupytext scripts.
|
|
2
|
+
|
|
3
|
+
Examples are percent-format `.py` files executed once in an ipykernel; each
|
|
4
|
+
displayed matplotlib figure is rendered for both themes from that single run
|
|
5
|
+
(see `zallery.theme`). [`build_gallery`][zallery.build_gallery] runs the whole
|
|
6
|
+
pipeline: discover, cache, execute, render, index.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from zallery.pipeline import build_gallery
|
|
10
|
+
|
|
11
|
+
__all__ = ["build_gallery"]
|