Search code examples
python-sphinxsubstitutionrestructuredtext

How to use substitution definitions with code blocks?


I tried using substitution definitions together with code blocks in Sphinx documentation however it doesn't work. This is my ReST source code:

.. |foo| code-block:: python

   foo = 1

|foo|

Sphinx throws the following errors:

/.../examples.rst:184: WARNING: Substitution definition "foo" empty or invalid.

.. |foo| code-block:: python

   foo = 1

/.../examples.rst:193: ERROR: Undefined substitution referenced: "foo".

How can I make this example work?


  • Sphinx version: 1.5.5 (using Sphinx 1.6.2 the above error transforms into a warning).

Solution

  • This is not possible without changing code-block. I have created a Sphinx extension which provides substitution-code-block for this purpose.

    It allows you to define substitutions in conf.py and then use these substitutions in .. substitution-code-block blocks.

    This extension is at https://github.com/adamtheturtle/sphinx-substitution-extensions.

    However, this is a very small amount of code. To enable this in your own codebase without a third party extension, create a module in your codebase with the following contents:

    """
    Custom Sphinx extensions.
    """
    
    from typing import List
    
    from sphinx.application import Sphinx
    from sphinx.directives.code import CodeBlock
    
    
    class SubstitutionCodeBlock(CodeBlock):  # type: ignore
        """
        Similar to CodeBlock but replaces placeholders with variables.
        """
    
        def run(self) -> List:
            """
            Replace placeholders with given variables.
            """
            app = self.state.document.settings.env.app
            new_content = []
            self.content = self.content  # type: List[str]
            existing_content = self.content
            for item in existing_content:
                for pair in app.config.substitutions:
                    original, replacement = pair
                    item = item.replace(original, replacement)
                new_content.append(item)
    
            self.content = new_content
            return list(CodeBlock.run(self))
    
    
    def setup(app: Sphinx) -> None:
        """
        Add the custom directives to Sphinx.
        """
        app.add_config_value('substitutions', [], 'html')
        app.add_directive('substitution-code-block', SubstitutionCodeBlock)
    

    Then, use this module the extensions defined in conf.py. Then, set the substitutions variable in conf.py e.g. to [('|foo|', 'bar')] to replace |foo| with bar in every substitution-code-block.