Sphinx Substitution Extensions
August 5, 2026 ยท View on GitHub
|Build Status| |PyPI|
Sphinx Substitution Extensions
Extensions for Sphinx which allow substitutions within code blocks.
.. contents::
Installation
Sphinx Substitution Extensions is compatible with Sphinx 8.2.0+ using Python |minimum-python-version|+.
.. code-block:: console
$ pip install Sphinx-Substitution-Extensions
rST setup
- Add the following to
conf.pyto enable the extension:
.. code-block:: python
"""Configuration for Sphinx."""
extensions = ["sphinxcontrib.spelling"] # Example existing extensions
extensions += ["sphinx_substitution_extensions"]
- Set the following variable in
conf.pyto define substitutions:
.. code-block:: python
"""Configuration for Sphinx."""
rst_prolog = """ .. |release| replace:: 0.1 .. |author| replace:: Eleanor """
This will replace |release| in the new directives with 0.1, and |author| with Eleanor.
Using substitutions in rST documents
code-block
This adds a ``:substitutions:`` option to Sphinx's built-in `code-block`_ directive.
.. code-block:: rst
.. code-block:: shell
:substitutions:
echo "|author| released version |release|"
Inline ``:substitution-code:``
.. code-block:: rst
:substitution-code:echo "|author| released version |release|"
substitution-download
.. code-block:: rst
:substitution-download:`|author|'s manuscript <|author|_manuscript.txt>`
External hyperlinks
~~~~~~~~~~~~~~~~~~~
Enable substitutions in external hyperlink targets in ``conf.py``:
.. code-block:: python
"""Configuration for Sphinx."""
substitutions_hyperlink_targets_enabled = True
Then substitutions are applied to hyperlink targets:
.. code-block:: rst
Download version |release| from the tarball_.
.. _tarball: https://example.com/releases/v|release|.tar.gz
The setting enables hyperlink-target substitutions throughout the project,
but only targets containing a defined substitution are changed. To limit a
substitution to one page, define it in that page instead of in
``rst_prolog``:
.. code-block:: rst
.. |tarball-release| replace:: 0.8.5
Download the tarball_.
.. _tarball: https://example.com/releases/v|tarball-release|.tar.gz
To limit the substitution to one link on that page, use a unique substitution
name, such as ``tarball-release`` above, only in that link's target. Other
hyperlink targets are left unchanged.
``literalinclude``
~~~~~~~~~~~~~~~~~~
This adds ``:content-substitutions:`` and ``:path-substitutions:`` options to Sphinx's built-in `literalinclude`_ directive.
Replace substitutions in the content of the included file:
.. code-block:: rst
.. literalinclude:: path/to/file.txt
:content-substitutions:
Replace substitutions in the file path:
.. code-block:: rst
.. literalinclude:: path/to/|author|_file.txt
:path-substitutions:
``include``
~~~~~~~~~~~
This adds ``:content-substitutions:`` and ``:path-substitutions:`` options to
docutils' built-in `include`_ directive.
Replace substitutions in the included source content before it is parsed:
.. code-block:: rst
.. include:: path/to/file.rst
:content-substitutions:
Replace substitutions in the file path:
.. code-block:: rst
.. include:: path/to/|author|_file.txt
:path-substitutions:
``image``
~~~~~~~~~
This adds a ``:path-substitutions:`` option to Sphinx's built-in `image`_ directive.
Replace substitutions in the image path:
.. code-block:: rst
.. image:: path/to/|author|_diagram.png
:path-substitutions:
:alt: Diagram
MyST Markdown setup
-------------------
1. Add ``sphinx_substitution_extensions`` to ``extensions`` in ``conf.py`` to enable the extension:
.. code-block:: python
"""Configuration for Sphinx."""
extensions = ["myst_parser"] # Example existing extensions
extensions += ["sphinx_substitution_extensions"]
2. Set the following variables in ``conf.py`` to define substitutions:
.. code-block:: python
"""Configuration for Sphinx."""
myst_enable_extensions = ["substitution"]
myst_substitutions = {
"release": "0.1",
"author": "Eleanor",
}
This will replace ``|release|`` in the new directives with ``0.1``, and ``|author|`` with ``Eleanor``.
Substitutions can also be defined or overridden for an individual Markdown
document in its frontmatter:
.. code-block:: markdown
---
myst:
substitutions:
release: "0.2"
author:
name: Talya
---
```{code-block} shell
:substitutions:
echo "|author.name| released version |release|"
```
Enabling substitutions by default
----------------------------------
By default, you need to explicitly add the ``:substitutions:`` flag to
``code-block`` directives, ``:content-substitutions:`` or
``:path-substitutions:`` flags to ``literalinclude`` and ``include``
directives, and ``:path-substitutions:`` to ``image`` directives.
If you want substitutions to be applied by default without needing these flags, you can set the following in ``conf.py``:
.. code-block:: python
"""Configuration for Sphinx."""
substitutions_default_enabled = True
When this is enabled:
- All ``code-block`` directives will have substitutions applied automatically
- All ``literalinclude`` directives will have both content and path substitutions applied automatically
- All ``include`` directives will have both content and path substitutions applied automatically
- All ``image`` directives will have path substitutions applied automatically
You can disable substitutions for specific directives when the default is enabled:
.. code-block:: rst
.. code-block:: shell
:nosubstitutions:
echo "This |will| not be substituted"
.. literalinclude:: path/to/file.txt
:nocontent-substitutions:
.. literalinclude:: path/to/|literal|_file.txt
:nopath-substitutions:
.. include:: path/to/|literal|_file.txt
:nocontent-substitutions:
:nopath-substitutions:
.. image:: path/to/|literal|_diagram.png
:nopath-substitutions:
Using substitutions in MyST Markdown
------------------------------------
``code-block``
~~~~~~~~~~~~~~
This adds a ``:substitutions:`` option to Sphinx's built-in `code-block`_ directive.
.. code-block:: markdown
```{code-block} bash
:substitutions:
echo "|author| released version |release|"
```
As well as using ``|author|``, you can also use ``{{author}}``.
This will respect the value of ``myst_sub_delimiters`` as set in ``conf.py``.
Inline ``:substitution-code:``
.. code-block:: rst
{substitution-code}echo "|author| released version |release|"
substitution-download
.. code-block:: rst
{substitution-download}`|author|'s manuscript <|author|_manuscript.txt>`
``literalinclude``
~~~~~~~~~~~~~~~~~~
This adds ``:content-substitutions:`` and ``:path-substitutions:`` options to Sphinx's built-in `literalinclude`_ directive.
Replace substitutions in the content of the included file:
.. code-block:: markdown
```{literalinclude} path/to/file.txt
:content-substitutions:
```
Replace substitutions in the file path:
.. code-block:: markdown
```{literalinclude} path/to/|author|_file.txt
:path-substitutions:
```
``include``
~~~~~~~~~~~
This adds a ``:path-substitutions:`` option to docutils' built-in `include`_ directive.
Replace substitutions in the file path:
.. code-block:: markdown
```{include} path/to/|author|_file.txt
:path-substitutions:
```
``image``
~~~~~~~~~
This adds a ``:path-substitutions:`` option to Sphinx's built-in `image`_ directive.
Replace substitutions in the image path:
.. code-block:: markdown
```{image} path/to/|author|_diagram.png
:path-substitutions:
:alt: Diagram
```
Nested substitutions
~~~~~~~~~~~~~~~~~~~~~
``myst_substitutions`` supports nested dictionaries and lists, which are flattened using dot notation.
**Important:** Substitution keys cannot contain dots (``.``), as dots are reserved for nested access notation.
For example, ``{"key.with.dots": "value"}`` raises an exception.
Nested dictionaries:
.. code-block:: python
"""Configuration for Sphinx."""
myst_substitutions = {
"app": {
"name": "MyApp",
"version": "1.0.0",
},
}
Usage in Markdown:
.. code-block:: markdown
```{code-block} bash
:substitutions:
echo "Application: |app.name| version |app.version|"
```
Lists with index access:
.. code-block:: python
"""Configuration for Sphinx."""
myst_substitutions = {
"platforms": ["Linux", "Windows", "macOS"],
}
Usage:
.. code-block:: markdown
```{code-block} bash
:substitutions:
echo "First platform: |platforms.0|"
echo "Second platform: |platforms.1|"
```
Nested lists of dictionaries:
.. code-block:: python
"""Configuration for Sphinx."""
myst_substitutions = {
"releases": [
{"version": "1.0", "codename": "Alpha"},
{"version": "2.0", "codename": "Beta"},
],
}
Usage:
.. code-block:: markdown
```{code-block} bash
:substitutions:
echo "First release: |releases.0.version| (|releases.0.codename|)"
echo "Second release: |releases.1.version| (|releases.1.codename|)"
```
Complex nested structures:
.. code-block:: python
"""Configuration for Sphinx."""
myst_substitutions = {
"project": {
"name": "MyProject",
"contributors": [
{"name": "Alice", "role": "dev"},
{"name": "Bob", "role": "docs"},
],
},
}
Usage:
.. code-block:: markdown
```{code-block} bash
:substitutions:
echo "Project: |project.name|"
echo "Developer: |project.contributors.0.name|"
echo "Documentation: |project.contributors.1.name|"
```
Credits
-------
ClusterHQ Developers
~~~~~~~~~~~~~~~~~~~~
This package is largely inspired by code written for Flocker by ClusterHQ.
Developers of the relevant code include, at least, Jon Giddy and Tom Prince.
Contributing
------------
See `CONTRIBUTING.rst <./CONTRIBUTING.rst>`_.
.. |Build Status| image:: https://github.com/adamtheturtle/sphinx-substitution-extensions/actions/workflows/ci.yml/badge.svg?branch=main
:target: https://github.com/adamtheturtle/sphinx-substitution-extensions/actions
.. _code-block: http://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block
.. _literalinclude: http://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-literalinclude
.. _include: https://docutils.sourceforge.io/docs/ref/rst/directives.html#including-an-external-document-fragment
.. _image: http://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-image
.. |PyPI| image:: https://badge.fury.io/py/Sphinx-Substitution-Extensions.svg
:target: https://badge.fury.io/py/Sphinx-Substitution-Extensions
.. |minimum-python-version| replace:: 3.11