pythonpython-sphinx

Documenting a script step by step with Sphinx


I am documenting a python library with Sphinx.

I have a couple of example scripts which I'd like to document in a narrative way, something like this:

#: Import necessary package and define :meth:`make_grid`
import numpy as np

def make_grid(a,b):
    """
    Make a grid for constant by piece functions
    """
    x = np.linspace(0,np.pi)
    xmid = (x[:-1]+x[1:])/2
    h = x[1:]-x[:-1]
    return xmid,h

#: Interpolate a function
xmid,h = make_grid(0,np.pi)
y = np.sin(xmid)

#: Calculate its integral
I = np.sum(y*h)
print ("Result %g" % I )

Those scripts should remain present as executable scripts in the repository, and I want to avoid duplicating their code into comments.

I would like to generate the corresponding documentation, something like :

sphinx output

Is there any automated way to do so? This would allow me not to duplicate the example script in the documentation. It seems to me this was the object of this old question but in my hands viewcode extension doesn't interpret comments, it just produces an html page with quoted code, comments remain comments.


Solution

  • Take a look at the sphinx-gallery extension, which seems to do what you require. With this extension, if you have a Python script, you must start it with a header docstring, and then you can add comments that will be formatted as text rather than code using the # %% syntax, e.g.,

    """
    My example script.
    """
    
    import numpy as np
    
    # %%
    # This will be a text block
    
    x = np.linspace(0, 10, 100)
    y = np.sin(2 * np.pi * x)
    
    # %%
    # Another block of text
    

    More details of the syntax is described here, and various examples are, e.g., here.

    Alternative option

    If the sphinx-gallery option is not appropriate (i.e., you don't really want a thumbnail-style gallery page linking to the examples), you could instead make use of the nbsphinx extension and the jupytext package. You can write your example Python scripts in jupytext's percent format, and then generate the pages via an intermediate conversion to a Jupyter notebook. For example (after installing both nbsphinx and jupytext), if you had a package structure like:

    .
    ├── docs
    │   ├── Makefile
    │   ├── conf.py
    │   ├── examples -> ../src/examples/
    │   ├── index.rst
    │   └── make.bat
    └── src
        └── examples
            └── narrative.py
    

    where in this case I've symbolic linked the src/examples directory into the docs directory, you could edit your Sphinx conf.py file to contain:

    
    # add nbsphinx to extensions
    extensions = [
      ...
      "nbsphinx",
    ]
    
    # this converts .py files with the percent format to notebooks
    nbsphinx_custom_formats = {
      '.py': ['jupytext.reads', {'fmt': 'py:percent'}],
    }
    nbsphinx_output_prompt = ""
    nbsphinx_execute = "auto"
    
    templates_path = ['_templates']
    # add conf.py to exclude_patterns
    exclude_patterns = [..., 'conf.py']
    

    and have narrative.py looking like:

    # %% [markdown]
    # # A title
    
    # %% [raw] raw_mimetype="text/restructuredtext"
    # Import necessary package and define :meth:`make_grid`
    
    # %%
    import numpy as np
    
    def make_grid(a,b):
        """
        Make a grid for constant by piece functions
        """
        x = np.linspace(0,np.pi)
        xmid = (x[:-1]+x[1:])/2
        h = x[1:]-x[:-1]
        return xmid,h
    
    # %% [markdown]
    # Interpolate a function
    
    # %%
    xmid,h = make_grid(0,np.pi)
    y = np.sin(xmid)
    
    # %% [markdown]
    # Calculate its integral
    
    # %%
    I = np.sum(y*h)
    print ("Result %g" % I )
    

    then running make html should produce a narrative.html file like:

    Example doc page

    which you can link to from index.rst etc. Some things to note about the narrative.py file: