sphinx-pyrunblock 1.0.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.
- sphinx_pyrunblock-1.0.0/.gitignore +8 -0
- sphinx_pyrunblock-1.0.0/AUTHORS +4 -0
- sphinx_pyrunblock-1.0.0/LICENCE +26 -0
- sphinx_pyrunblock-1.0.0/PKG-INFO +90 -0
- sphinx_pyrunblock-1.0.0/README.md +61 -0
- sphinx_pyrunblock-1.0.0/docs/figs/pyrunblock-logo.svg +15 -0
- sphinx_pyrunblock-1.0.0/docs/source/_static/.gitkeep +0 -0
- sphinx_pyrunblock-1.0.0/docs/source/about.rst +68 -0
- sphinx_pyrunblock-1.0.0/docs/source/conf.py +46 -0
- sphinx_pyrunblock-1.0.0/docs/source/configuration.rst +100 -0
- sphinx_pyrunblock-1.0.0/docs/source/index.rst +175 -0
- sphinx_pyrunblock-1.0.0/pyproject.toml +74 -0
- sphinx_pyrunblock-1.0.0/rename-plan.md +179 -0
- sphinx_pyrunblock-1.0.0/src/sphinx_pyrunblock/__init__.py +51 -0
- sphinx_pyrunblock-1.0.0/src/sphinx_pyrunblock/config.py +28 -0
- sphinx_pyrunblock-1.0.0/src/sphinx_pyrunblock/directive.py +181 -0
- sphinx_pyrunblock-1.0.0/src/sphinx_pyrunblock/interpreter.py +159 -0
- sphinx_pyrunblock-1.0.0/src/sphinx_pyrunblock/utils.py +40 -0
- sphinx_pyrunblock-1.0.0/tech-debt.md +56 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Copyright (c) 2020-2026, Peter Corke.
|
|
2
|
+
Copyright (c) 2009-2017, The Contributors (see AUTHORS file).
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are
|
|
7
|
+
met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
13
|
+
notice, this list of conditions and the following disclaimer in the
|
|
14
|
+
documentation and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
20
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
21
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
22
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
23
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
24
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
26
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sphinx-pyrunblock
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Sphinx extension that executes code and embeds real output in docs (.. runblock:: directive)
|
|
5
|
+
Project-URL: Homepage, https://github.com/petercorke/sphinx-pyrunblock
|
|
6
|
+
Project-URL: Bug Tracker, https://github.com/petercorke/sphinx-pyrunblock/issues
|
|
7
|
+
Project-URL: Documentation, https://petercorke.github.io/sphinx-pyrunblock
|
|
8
|
+
Project-URL: GitHub Source, https://github.com/petercorke/sphinx-pyrunblock
|
|
9
|
+
Project-URL: Changelog, https://github.com/petercorke/sphinx-pyrunblock/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Peter Corke <rvc@petercorke.com>, Hugo Osvaldo Barrera <hugo@barrera.io>
|
|
11
|
+
License-Expression: BSD-2-Clause
|
|
12
|
+
License-File: LICENCE
|
|
13
|
+
Keywords: doctest,documentation,runblock,sphinx
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: sphinx>=4.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: coverage; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
<div align="center">
|
|
31
|
+
<img src="https://github.com/petercorke/sphinx-pyrunblock/raw/main/docs/figs/pyrunblock-logo.svg" width="350">
|
|
32
|
+
<br><br>
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/sphinx-pyrunblock/)
|
|
35
|
+
[](https://petercorke.github.io/sphinx-pyrunblock/)
|
|
36
|
+
[](https://github.com/petercorke/sphinx-pyrunblock/actions/workflows/ci.yml)
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
# sphinx-pyrunblock
|
|
40
|
+
|
|
41
|
+
Fast, in-process embedding of live Python code output into your Sphinx docs.
|
|
42
|
+
`sphinx-pyrunblock` runs each `.. runblock::` example directly in a shared
|
|
43
|
+
interpreter rather than spawning a subprocess per block — and it's backward
|
|
44
|
+
compatible with `sphinx-autorun`: same `runblock` directive, same
|
|
45
|
+
`autorun_languages` config shape, drop-in upgrade.
|
|
46
|
+
|
|
47
|
+
```rst
|
|
48
|
+
.. runblock:: pycon
|
|
49
|
+
|
|
50
|
+
>>> for i in range(5):
|
|
51
|
+
... print(i)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Produces:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
>>> for i in range(5):
|
|
58
|
+
... print(i)
|
|
59
|
+
0
|
|
60
|
+
1
|
|
61
|
+
2
|
|
62
|
+
3
|
|
63
|
+
4
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
$ pip install sphinx-pyrunblock
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Enable the extension by adding it to the `extensions` list in `conf.py`:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
extensions.append("sphinx_pyrunblock")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
See the [full documentation](https://petercorke.github.io/sphinx-pyrunblock/)
|
|
79
|
+
for configuration (`conf.py` options, `runfirst` setup), per-block directive
|
|
80
|
+
options (`:numpy:`, `:scipy:`, `:smtb:`, `:precision:`, `:include:`,
|
|
81
|
+
`:exclude:`), and how errors are reported during a build.
|
|
82
|
+
|
|
83
|
+
## Heritage
|
|
84
|
+
|
|
85
|
+
`sphinx-pyrunblock` began as a fork of
|
|
86
|
+
[sphinx-autorun](https://github.com/WhyNotHugo/sphinx-autorun) by Hugo
|
|
87
|
+
Osvaldo Barrera, itself descended from Vadim Gubergrits' original
|
|
88
|
+
`sphinxcontrib-autorun`. See the
|
|
89
|
+
[full history](https://petercorke.github.io/sphinx-pyrunblock/about.html)
|
|
90
|
+
for the complete lineage.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://github.com/petercorke/sphinx-pyrunblock/raw/main/docs/figs/pyrunblock-logo.svg" width="350">
|
|
3
|
+
<br><br>
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/sphinx-pyrunblock/)
|
|
6
|
+
[](https://petercorke.github.io/sphinx-pyrunblock/)
|
|
7
|
+
[](https://github.com/petercorke/sphinx-pyrunblock/actions/workflows/ci.yml)
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
# sphinx-pyrunblock
|
|
11
|
+
|
|
12
|
+
Fast, in-process embedding of live Python code output into your Sphinx docs.
|
|
13
|
+
`sphinx-pyrunblock` runs each `.. runblock::` example directly in a shared
|
|
14
|
+
interpreter rather than spawning a subprocess per block — and it's backward
|
|
15
|
+
compatible with `sphinx-autorun`: same `runblock` directive, same
|
|
16
|
+
`autorun_languages` config shape, drop-in upgrade.
|
|
17
|
+
|
|
18
|
+
```rst
|
|
19
|
+
.. runblock:: pycon
|
|
20
|
+
|
|
21
|
+
>>> for i in range(5):
|
|
22
|
+
... print(i)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Produces:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
>>> for i in range(5):
|
|
29
|
+
... print(i)
|
|
30
|
+
0
|
|
31
|
+
1
|
|
32
|
+
2
|
|
33
|
+
3
|
|
34
|
+
4
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
$ pip install sphinx-pyrunblock
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Enable the extension by adding it to the `extensions` list in `conf.py`:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
extensions.append("sphinx_pyrunblock")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
See the [full documentation](https://petercorke.github.io/sphinx-pyrunblock/)
|
|
50
|
+
for configuration (`conf.py` options, `runfirst` setup), per-block directive
|
|
51
|
+
options (`:numpy:`, `:scipy:`, `:smtb:`, `:precision:`, `:include:`,
|
|
52
|
+
`:exclude:`), and how errors are reported during a build.
|
|
53
|
+
|
|
54
|
+
## Heritage
|
|
55
|
+
|
|
56
|
+
`sphinx-pyrunblock` began as a fork of
|
|
57
|
+
[sphinx-autorun](https://github.com/WhyNotHugo/sphinx-autorun) by Hugo
|
|
58
|
+
Osvaldo Barrera, itself descended from Vadim Gubergrits' original
|
|
59
|
+
`sphinxcontrib-autorun`. See the
|
|
60
|
+
[full history](https://petercorke.github.io/sphinx-pyrunblock/about.html)
|
|
61
|
+
for the complete lineage.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<svg width="500" height="120" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Document Outline -->
|
|
3
|
+
<path d="M30 20 h 30 l 20 20 v 60 h -50 Z" fill="none" stroke="#2C3E50" stroke-width="4" stroke-linejoin="round"/>
|
|
4
|
+
<path d="M60 20 v 20 h 20" fill="none" stroke="#2C3E50" stroke-width="4" stroke-linejoin="round"/>
|
|
5
|
+
|
|
6
|
+
<!-- Terminal Bottom Half -->
|
|
7
|
+
<rect x="20" y="60" width="70" height="45" rx="4" fill="#2C3E50" />
|
|
8
|
+
|
|
9
|
+
<!-- Terminal Prompt -->
|
|
10
|
+
<text x="30" y="90" font-family="monospace" font-size="18" fill="#FFB300" font-weight="bold">>_</text>
|
|
11
|
+
|
|
12
|
+
<!-- Typography Header -->
|
|
13
|
+
<text x="110" y="80" font-family="sans-serif" font-size="36" fill="#2C3E50" font-weight="800" letter-spacing="-1">sphinx-</text>
|
|
14
|
+
<text x="245" y="80" font-family="monospace" font-size="36" fill="#FFB300" font-weight="bold">pyrunblock</text>
|
|
15
|
+
</svg>
|
|
File without changes
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
About this project
|
|
2
|
+
====================
|
|
3
|
+
|
|
4
|
+
``sphinx-pyrunblock`` is a hard fork of `sphinx-autorun
|
|
5
|
+
<https://github.com/WhyNotHugo/sphinx-autorun>`_ by Hugo Osvaldo Barrera,
|
|
6
|
+
itself several generations descended from the original
|
|
7
|
+
``sphinxcontrib-autorun`` by Vadim Gubergrits. Full acknowledgement of
|
|
8
|
+
that lineage lives on this page; :file:`LICENCE` and :file:`AUTHORS` in
|
|
9
|
+
the repository root carry the legal/contributor record.
|
|
10
|
+
|
|
11
|
+
Lineage
|
|
12
|
+
-------
|
|
13
|
+
|
|
14
|
+
Oldest to newest, verified against this repository's own git history
|
|
15
|
+
where the line passes directly through it (marked *verified* below), and
|
|
16
|
+
from research at the time of the 2026 rename otherwise:
|
|
17
|
+
|
|
18
|
+
- **sphinxcontrib-autorun** (Vadim Gubergrits, starting 2010-03-04
|
|
19
|
+
*(verified: first commit* ``1b76446``\ *)*, hosted on the old
|
|
20
|
+
Bitbucket-based ``sphinx-contrib`` collection). Michael McNeil Forbes
|
|
21
|
+
contributed to this original project too (*verified*: commit
|
|
22
|
+
``be1cbd3``, 2012-11-19).
|
|
23
|
+
- **sphinxcontrib-autorun2** (David Wolever, 2014) -- a parallel fork
|
|
24
|
+
published under a new name rather than a continuation; sphinx-contrib
|
|
25
|
+
forks were commonly released this way rather than via commit rights to
|
|
26
|
+
the original. Not part of this project's direct line.
|
|
27
|
+
- **sphinx-autorun-ng** (Hugo Osvaldo Barrera, 2017) -- dropped the
|
|
28
|
+
``sphinxcontrib`` namespace, moved off Bitbucket. Released once, then
|
|
29
|
+
immediately renamed.
|
|
30
|
+
- **sphinx-autorun** (same Hugo Osvaldo Barrera, 2017 onward, i.e.
|
|
31
|
+
``WhyNotHugo`` on GitHub *(verified: this repository's own git history
|
|
32
|
+
contains Hugo's "Fork into sphinx_autorun" commit,* ``dc9c315``\ *,
|
|
33
|
+
2017-01-10)* -- this is the project still actively maintained today,
|
|
34
|
+
and the one the ``sphinx-autorun`` name on PyPI resolves to.
|
|
35
|
+
- A separate one-off side-branch, **sphinx-autorun-ebs** (Endre Bakken
|
|
36
|
+
Stovner, 2018, one release), also exists but was never touched again
|
|
37
|
+
and isn't part of this line.
|
|
38
|
+
- **sphinx-pyrunblock** (Peter Corke) -- this project. Forked from
|
|
39
|
+
``WhyNotHugo/sphinx-autorun`` 2020-10-26 *(verified: first commit*
|
|
40
|
+
``2549daa``, *"Eliminate the line buffering error"*\ *)*. The fix was
|
|
41
|
+
also submitted upstream the same day, as `PR #19
|
|
42
|
+
<https://github.com/WhyNotHugo/sphinx-autorun/pull/19>`_ -- it sat open
|
|
43
|
+
for over four years and was eventually closed 2025-01-02 in favour of
|
|
44
|
+
`PR #65 <https://github.com/WhyNotHugo/sphinx-autorun/pull/65>`_, a
|
|
45
|
+
different, simpler fix for the same underlying bug submitted by another
|
|
46
|
+
contributor and merged that same day.
|
|
47
|
+
|
|
48
|
+
No further commits landed in this fork until a rewrite arrived
|
|
49
|
+
2025-01-12, replacing the original subprocess-per-block execution with
|
|
50
|
+
a single, shared, in-process interpreter -- the change this project's
|
|
51
|
+
speed comes from. That rewrite was motivated by real docs-build time
|
|
52
|
+
becoming a pain point during the push to ship Robotics Toolbox for
|
|
53
|
+
Python and Machine Vision Toolbox for Python, both of which use this
|
|
54
|
+
extension to execute live code examples during their own documentation
|
|
55
|
+
builds.
|
|
56
|
+
|
|
57
|
+
Why a hard fork
|
|
58
|
+
----------------
|
|
59
|
+
|
|
60
|
+
``sphinx-autorun`` was never published to PyPI under that name from this
|
|
61
|
+
line of descent -- ``sphinx-autorun`` on PyPI is, and remains, Hugo
|
|
62
|
+
Osvaldo Barrera's actively-maintained project. Publishing this project's
|
|
63
|
+
own substantially rewritten execution engine under an unrelated,
|
|
64
|
+
already-claimed name wasn't viable, hence the rename to
|
|
65
|
+
``sphinx-pyrunblock`` and a clean detachment from the GitHub fork
|
|
66
|
+
network it started in. The directive name (``.. runblock::``) is
|
|
67
|
+
unchanged, and existing ``conf.py`` ``autorun_languages`` configuration
|
|
68
|
+
carries over -- only the package/import name differs.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Configuration file for the Sphinx documentation builder.
|
|
2
|
+
#
|
|
3
|
+
# For the full list of built-in configuration values, see the documentation:
|
|
4
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
5
|
+
|
|
6
|
+
# -- Project information -----------------------------------------------------
|
|
7
|
+
|
|
8
|
+
from sphinx_pyrunblock import __version__
|
|
9
|
+
|
|
10
|
+
project = "sphinx-pyrunblock"
|
|
11
|
+
copyright = "2020-2026, Peter Corke"
|
|
12
|
+
author = "Peter Corke"
|
|
13
|
+
release = __version__
|
|
14
|
+
version = __version__
|
|
15
|
+
|
|
16
|
+
# -- General configuration ---------------------------------------------------
|
|
17
|
+
|
|
18
|
+
extensions = [
|
|
19
|
+
"sphinx_pyrunblock",
|
|
20
|
+
"sphinx.ext.autosectionlabel",
|
|
21
|
+
]
|
|
22
|
+
autosectionlabel_prefix_document = True
|
|
23
|
+
|
|
24
|
+
templates_path = ["_templates"]
|
|
25
|
+
exclude_patterns = []
|
|
26
|
+
|
|
27
|
+
# -- sphinx-pyrunblock setup --------------------------------------------------
|
|
28
|
+
# Python session setup shared by every runblock example on this site: turn
|
|
29
|
+
# off SE3/ANSITable colour codes (they don't render usefully as plain HTML
|
|
30
|
+
# text) and fix numpy's print precision so output is stable across builds.
|
|
31
|
+
autorun_languages = {}
|
|
32
|
+
autorun_languages[
|
|
33
|
+
"pycon_runfirst"
|
|
34
|
+
] = """
|
|
35
|
+
from spatialmath import SE3
|
|
36
|
+
SE3._color = False
|
|
37
|
+
import numpy as np
|
|
38
|
+
np.set_printoptions(precision=4, suppress=True)
|
|
39
|
+
from ansitable import ANSITable
|
|
40
|
+
ANSITable._color = False
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# -- Options for HTML output -------------------------------------------------
|
|
44
|
+
|
|
45
|
+
html_theme = "alabaster"
|
|
46
|
+
html_static_path = ["_static"]
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Configuration
|
|
2
|
+
=============
|
|
3
|
+
|
|
4
|
+
``sphinx-pyrunblock`` is configured through a single ``conf.py`` dict,
|
|
5
|
+
``autorun_languages``. This page is the complete reference for it. For
|
|
6
|
+
options that apply to one ``runblock`` directive invocation rather than
|
|
7
|
+
the whole document, see :ref:`per-block options <index:Per-block options>`.
|
|
8
|
+
|
|
9
|
+
The ``autorun_languages`` dict
|
|
10
|
+
-------------------------------
|
|
11
|
+
|
|
12
|
+
.. code-block:: python
|
|
13
|
+
|
|
14
|
+
autorun_languages = {}
|
|
15
|
+
autorun_languages["pycon_runfirst"] = "..."
|
|
16
|
+
|
|
17
|
+
The dict's keys are **not** language names in the usual sense -- ``pycon``
|
|
18
|
+
is really the only supported language, a historical artifact of an earlier
|
|
19
|
+
design that also executed a ``console`` (bash) language via a separate
|
|
20
|
+
subprocess. That's no longer how this extension works: every block runs
|
|
21
|
+
in a single, shared, in-process ``code.InteractiveInterpreter``, which is
|
|
22
|
+
what makes it fast (no subprocess spawned per code block). Think of
|
|
23
|
+
``pycon`` as the key *prefix* under which each of the settings below is
|
|
24
|
+
namespaced, rather than a literal interpreter selection.
|
|
25
|
+
|
|
26
|
+
At Sphinx's ``builder-inited`` event, whatever you set in
|
|
27
|
+
``autorun_languages`` is merged on top of the extension's own defaults
|
|
28
|
+
(``pycon``, ``pycon_prefix_chars``, ``pycon_show_source``). You only need
|
|
29
|
+
to set the keys you want to change.
|
|
30
|
+
|
|
31
|
+
Per-language keys
|
|
32
|
+
------------------
|
|
33
|
+
|
|
34
|
+
``<lang>``
|
|
35
|
+
Declares ``<lang>`` a valid argument to the ``runblock`` directive
|
|
36
|
+
(e.g. ``.. runblock:: pycon`` requires ``"pycon"`` to be a key in the
|
|
37
|
+
merged config). The *value* itself is vestigial -- it dates from the
|
|
38
|
+
old subprocess-per-language design, where it was the shell command to
|
|
39
|
+
pipe code into. It isn't read for anything today; only the key's
|
|
40
|
+
presence matters.
|
|
41
|
+
|
|
42
|
+
``<lang>_prefix_chars``
|
|
43
|
+
Number of characters to strip from the start of each prompted line
|
|
44
|
+
(``>>>`` or ``...``, plus the following space) before executing it.
|
|
45
|
+
Defaults to ``0`` if unset; the built-in ``pycon`` default is ``4``,
|
|
46
|
+
matching the length of ``"``>>> ``"``.
|
|
47
|
+
|
|
48
|
+
``<lang>_show_source``
|
|
49
|
+
If true, echo each line of source to the Sphinx build log as it runs
|
|
50
|
+
(useful when debugging a block that isn't producing the output you
|
|
51
|
+
expect). Defaults to ``False``.
|
|
52
|
+
|
|
53
|
+
``<lang>_runfirst``
|
|
54
|
+
A newline-separated string of Python statements, **without prompts**,
|
|
55
|
+
executed once before every ``runblock:: <lang>`` block in the
|
|
56
|
+
document, in the same shared interpreter session. Doesn't appear in
|
|
57
|
+
the rendered output. This is the main per-project customisation
|
|
58
|
+
point -- typically used to import commonly-used modules and set up
|
|
59
|
+
formatting/print options once, rather than repeating it in every
|
|
60
|
+
example.
|
|
61
|
+
|
|
62
|
+
A full worked example
|
|
63
|
+
-----------------------
|
|
64
|
+
|
|
65
|
+
This is the actual ``pycon_runfirst`` used to build this documentation
|
|
66
|
+
(also representative of what Peter's other toolboxes use): it silences
|
|
67
|
+
colour-code output from two libraries that would otherwise embed raw
|
|
68
|
+
ANSI escapes in the HTML, and fixes numpy's print precision so output is
|
|
69
|
+
stable across builds.
|
|
70
|
+
|
|
71
|
+
.. code-block:: python
|
|
72
|
+
|
|
73
|
+
autorun_languages = {}
|
|
74
|
+
autorun_languages[
|
|
75
|
+
"pycon_runfirst"
|
|
76
|
+
] = """
|
|
77
|
+
from spatialmath import SE3
|
|
78
|
+
SE3._color = False
|
|
79
|
+
import numpy as np
|
|
80
|
+
np.set_printoptions(precision=4, suppress=True)
|
|
81
|
+
from ansitable import ANSITable
|
|
82
|
+
ANSITable._color = False
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
Gotchas
|
|
86
|
+
-------
|
|
87
|
+
|
|
88
|
+
- The directive's ``:numpy:``/``:scipy:`` options (see
|
|
89
|
+
:ref:`per-block options <index:Per-block options>`) layer **on top of**
|
|
90
|
+
``<lang>_runfirst`` -- they don't replace it. ``<lang>_runfirst`` always
|
|
91
|
+
runs first, then any per-block imports requested via directive options.
|
|
92
|
+
- ``:precision: N`` calls ``np.set_printoptions``, so numpy must already
|
|
93
|
+
be imported by that point -- either via ``:numpy:`` on the same
|
|
94
|
+
directive, or because ``<lang>_runfirst`` already imports it.
|
|
95
|
+
- ``<lang>_prefix_chars`` only strips characters from lines that actually
|
|
96
|
+
start with a prompt (``>>>`` or ``...``, plus the following space). A
|
|
97
|
+
bare continuation line (for example, the body of a triple-quoted string
|
|
98
|
+
spanning several lines) is
|
|
99
|
+
left untouched, so multi-line string literals in your examples render
|
|
100
|
+
correctly.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
sphinx-pyrunblock
|
|
2
|
+
==================
|
|
3
|
+
|
|
4
|
+
.. image:: ../figs/pyrunblock-logo.svg
|
|
5
|
+
:align: center
|
|
6
|
+
:width: 350
|
|
7
|
+
:alt: sphinx-pyrunblock
|
|
8
|
+
|
|
9
|
+
``sphinx-pyrunblock`` is a Sphinx extension that executes code from a
|
|
10
|
+
``runblock`` directive and inserts the real output into your documentation.
|
|
11
|
+
For example::
|
|
12
|
+
|
|
13
|
+
.. runblock:: pycon
|
|
14
|
+
|
|
15
|
+
>>> for i in range(5):
|
|
16
|
+
... print(i)
|
|
17
|
+
|
|
18
|
+
produces:
|
|
19
|
+
|
|
20
|
+
.. runblock:: pycon
|
|
21
|
+
|
|
22
|
+
>>> for i in range(5):
|
|
23
|
+
... print(i)
|
|
24
|
+
|
|
25
|
+
.. toctree::
|
|
26
|
+
:maxdepth: 2
|
|
27
|
+
:caption: Contents:
|
|
28
|
+
|
|
29
|
+
configuration
|
|
30
|
+
about
|
|
31
|
+
|
|
32
|
+
Installation
|
|
33
|
+
------------
|
|
34
|
+
|
|
35
|
+
.. code-block:: console
|
|
36
|
+
|
|
37
|
+
$ pip install sphinx-pyrunblock
|
|
38
|
+
|
|
39
|
+
Enable the extension by adding it to the ``extensions`` list in ``conf.py``:
|
|
40
|
+
|
|
41
|
+
.. code-block:: python
|
|
42
|
+
|
|
43
|
+
extensions = [
|
|
44
|
+
"sphinx_pyrunblock",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
See :doc:`configuration` for the full ``conf.py`` reference.
|
|
48
|
+
|
|
49
|
+
Worked examples
|
|
50
|
+
----------------
|
|
51
|
+
|
|
52
|
+
.. runblock:: pycon
|
|
53
|
+
|
|
54
|
+
>>> from spatialmath.base import trnorm, troty
|
|
55
|
+
>>> from numpy import linalg
|
|
56
|
+
>>> T = troty(45, 'deg', t=[3, 4, 5])
|
|
57
|
+
>>> linalg.det(T[:3,:3]) - 1 # is a valid SO(3)
|
|
58
|
+
>>> T = T @ T @ T @ T @ T @ T @ T @ T @ T @ T @ T @ T @ T
|
|
59
|
+
>>> linalg.det(T[:3,:3]) - 1 # not quite a valid SE(3) anymore
|
|
60
|
+
>>> T = trnorm(T)
|
|
61
|
+
>>> linalg.det(T[:3,:3]) - 1 # once more a valid SE(3)
|
|
62
|
+
|
|
63
|
+
.. runblock:: pycon
|
|
64
|
+
|
|
65
|
+
>>> from spatialmath.base import qconj, qprint
|
|
66
|
+
>>> q = [1, 2, 3, 4]
|
|
67
|
+
>>> qprint(qconj(q))
|
|
68
|
+
|
|
69
|
+
Per-block options
|
|
70
|
+
------------------
|
|
71
|
+
|
|
72
|
+
Options are given on the directive itself, and apply to that one block only
|
|
73
|
+
(compare :doc:`configuration` for options that apply document-wide, via
|
|
74
|
+
``conf.py``):
|
|
75
|
+
|
|
76
|
+
``:linenos:``
|
|
77
|
+
Show line numbers in the rendered code block.
|
|
78
|
+
|
|
79
|
+
``:include: start-end``
|
|
80
|
+
Only render lines in the given range of the block's *output* (line
|
|
81
|
+
numbers count the block's own statements, not the configured
|
|
82
|
+
``runfirst`` code, which never appears in output).
|
|
83
|
+
|
|
84
|
+
``:exclude: start-end``
|
|
85
|
+
Skip lines in the given range, same numbering as ``:include:``.
|
|
86
|
+
|
|
87
|
+
``:numpy:``
|
|
88
|
+
Prepend ``import numpy as np`` before the block runs.
|
|
89
|
+
|
|
90
|
+
``:scipy:``
|
|
91
|
+
Prepend ``import scipy as sp`` before the block runs.
|
|
92
|
+
|
|
93
|
+
``:smtb:``
|
|
94
|
+
Append ``from spatialmath import *`` before the block runs.
|
|
95
|
+
|
|
96
|
+
``:precision: N``
|
|
97
|
+
Append ``np.set_printoptions(precision=N)`` before the block runs.
|
|
98
|
+
Requires numpy to already be imported (via ``:numpy:`` or a configured
|
|
99
|
+
``runfirst`` -- see :doc:`configuration`).
|
|
100
|
+
|
|
101
|
+
.. runblock:: pycon
|
|
102
|
+
:include: 5-10
|
|
103
|
+
|
|
104
|
+
>>> from spatialmath.base import getunit
|
|
105
|
+
>>> import numpy as np
|
|
106
|
+
>>> getunit(1.5, 'rad')
|
|
107
|
+
>>> getunit(90, 'deg')
|
|
108
|
+
>>> getunit(90, 'deg', vector=False) # force a scalar output
|
|
109
|
+
>>> getunit(1.5, 'rad', dim=0) # check argument is scalar
|
|
110
|
+
>>> getunit(1.5, 'rad', dim=3) # check argument is a 3-vector
|
|
111
|
+
>>> getunit([1.5], 'rad', dim=1) # check argument is a 1-vector
|
|
112
|
+
>>> getunit([1.5], 'rad', dim=3) # check argument is a 3-vector
|
|
113
|
+
>>> getunit(90, 'deg')
|
|
114
|
+
>>> getunit([90, 180], 'deg')
|
|
115
|
+
>>> getunit(np.r_[0.5, 1], 'rad')
|
|
116
|
+
>>> getunit(np.r_[90, 180], 'deg')
|
|
117
|
+
>>> getunit(np.r_[90, 180], 'deg', dim=2)
|
|
118
|
+
>>> getunit([90, 180, 270], 'deg', dim=3)
|
|
119
|
+
|
|
120
|
+
For any construct with an indented body (``for``, ``while``, ``with``), it's
|
|
121
|
+
important to put a blank line on the end. That will be stripped off and
|
|
122
|
+
won't appear in the output.
|
|
123
|
+
|
|
124
|
+
.. runblock:: pycon
|
|
125
|
+
:numpy:
|
|
126
|
+
|
|
127
|
+
>>> from spatialmath.base import getunit
|
|
128
|
+
>>> getunit(1.5, 'rad')
|
|
129
|
+
>>> try:
|
|
130
|
+
>>> getunit(1.5, 'rad', dim=0)
|
|
131
|
+
>>> except Exception as e:
|
|
132
|
+
>>> print(f"EXCEPTION {e}")
|
|
133
|
+
>>>
|
|
134
|
+
>>> for i in range(5):
|
|
135
|
+
>>> print(i)
|
|
136
|
+
>>>
|
|
137
|
+
|
|
138
|
+
Lines ending with ``# ignore`` are executed but not shown in the rendered
|
|
139
|
+
output -- useful for setup code that would otherwise clutter the example.
|
|
140
|
+
|
|
141
|
+
Error reporting
|
|
142
|
+
----------------
|
|
143
|
+
|
|
144
|
+
If the code raises an exception, a diagnostic marker is written to the
|
|
145
|
+
Sphinx build log and a short error summary is embedded in the rendered
|
|
146
|
+
output:
|
|
147
|
+
|
|
148
|
+
.. code-block:: text
|
|
149
|
+
|
|
150
|
+
>>> img.metadata('FocalLength')
|
|
151
|
+
!! [RUNBLOCK-ERROR] machinevisiontoolbox/ImageIO.py:236
|
|
152
|
+
KeyError: 'FocalLength'
|
|
153
|
+
|
|
154
|
+
The build log entry is more detailed:
|
|
155
|
+
|
|
156
|
+
.. code-block:: text
|
|
157
|
+
|
|
158
|
+
!! [RUNBLOCK-ERROR] source/numpy.rst:98
|
|
159
|
+
ModuleNotFoundError: No module named 'machinevisionToolbox'
|
|
160
|
+
Traceback (most recent call last):
|
|
161
|
+
File "<input>", line 1, in <module>
|
|
162
|
+
ModuleNotFoundError: No module named 'machinevisionToolbox'
|
|
163
|
+
|
|
164
|
+
The marker line appears **before** the traceback so failures are easy to
|
|
165
|
+
scan in a long build log. The source location (``file:line``) refers to the
|
|
166
|
+
``.rst`` file, or the Python source file containing the docstring where the
|
|
167
|
+
``runblock`` directive lives.
|
|
168
|
+
|
|
169
|
+
A syntax error in the code block is reported the same way:
|
|
170
|
+
|
|
171
|
+
.. code-block:: text
|
|
172
|
+
|
|
173
|
+
>>> print(("Hello, world")
|
|
174
|
+
!! [RUNBLOCK-ERROR] source/api.rst:42
|
|
175
|
+
SyntaxError: '(' was never closed
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
|
|
3
|
+
authors = [
|
|
4
|
+
{ name = "Peter Corke", email = "rvc@petercorke.com" },
|
|
5
|
+
{ name = "Hugo Osvaldo Barrera", email = "hugo@barrera.io" },
|
|
6
|
+
]
|
|
7
|
+
name = "sphinx-pyrunblock"
|
|
8
|
+
version = "1.0.0"
|
|
9
|
+
description = "Sphinx extension that executes code and embeds real output in docs (.. runblock:: directive)"
|
|
10
|
+
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
license = "BSD-2-Clause"
|
|
13
|
+
license-files = ["LICENCE"]
|
|
14
|
+
requires-python = ">=3.9"
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 5 - Production/Stable",
|
|
17
|
+
# Indicate who your project is intended for
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
# Specify the Python versions you support here.
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
]
|
|
28
|
+
keywords = ["sphinx", "documentation", "doctest", "runblock"]
|
|
29
|
+
|
|
30
|
+
dependencies = ["Sphinx>=4.0"]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
|
|
34
|
+
"Homepage" = "https://github.com/petercorke/sphinx-pyrunblock"
|
|
35
|
+
"Bug Tracker" = "https://github.com/petercorke/sphinx-pyrunblock/issues"
|
|
36
|
+
"Documentation" = "https://petercorke.github.io/sphinx-pyrunblock"
|
|
37
|
+
"GitHub Source" = "https://github.com/petercorke/sphinx-pyrunblock"
|
|
38
|
+
"Changelog" = "https://github.com/petercorke/sphinx-pyrunblock/blob/main/CHANGELOG.md"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
dev = ["pytest", "coverage", "ruff"]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
pythonpath = ["src"]
|
|
46
|
+
testpaths = ["tests"]
|
|
47
|
+
addopts = "--tb=short"
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 88
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E", "F", "I"]
|
|
54
|
+
|
|
55
|
+
[tool.ruff.lint.isort]
|
|
56
|
+
known-first-party = ["sphinx_pyrunblock"]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
[build-system]
|
|
60
|
+
requires = ["hatchling"]
|
|
61
|
+
build-backend = "hatchling.build"
|
|
62
|
+
|
|
63
|
+
[tool.hatch.build.targets.wheel]
|
|
64
|
+
packages = ["src/sphinx_pyrunblock"]
|
|
65
|
+
|
|
66
|
+
[tool.hatch.build.targets.sdist]
|
|
67
|
+
exclude = ["/test", "/tests", "/.git", "/.github", "/.claude", "/.vscode"]
|
|
68
|
+
|
|
69
|
+
[tool.black]
|
|
70
|
+
line-length = 88
|
|
71
|
+
target-version = ["py39", "py310", "py311", "py312", "py313"]
|
|
72
|
+
|
|
73
|
+
[tool.coverage.run]
|
|
74
|
+
omit = []
|