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.
@@ -0,0 +1,8 @@
1
+ .tox
2
+ *.pyc
3
+ .eggs
4
+ build
5
+ dist
6
+ *.egg-info
7
+ .claude
8
+ .DS_Store
@@ -0,0 +1,4 @@
1
+ Peter Corke <rvc@petercorke.com>
2
+ Hugo Osvaldo Barrera <hugo@barrera.io>
3
+ Michael McNeil Forbes <mforbes@physics.ubc.ca>
4
+ Vadim Gubergrits <vadim@outboxtechnology.com>
@@ -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
+ [![PyPI version](https://img.shields.io/pypi/v/sphinx-pyrunblock?style=for-the-badge&color=blue)](https://pypi.org/project/sphinx-pyrunblock/)
35
+ [![Documentation](https://img.shields.io/badge/Docs-View_Online-blue?style=for-the-badge)](https://petercorke.github.io/sphinx-pyrunblock/)
36
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/petercorke/sphinx-pyrunblock/ci.yml?branch=main&style=for-the-badge)](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
+ [![PyPI version](https://img.shields.io/pypi/v/sphinx-pyrunblock?style=for-the-badge&color=blue)](https://pypi.org/project/sphinx-pyrunblock/)
6
+ [![Documentation](https://img.shields.io/badge/Docs-View_Online-blue?style=for-the-badge)](https://petercorke.github.io/sphinx-pyrunblock/)
7
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/petercorke/sphinx-pyrunblock/ci.yml?branch=main&style=for-the-badge)](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">&gt;_</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 = []