IAM

ARTICLE

Setting up Sphinx to Document Python Projects

Sphinx is a Python documentation tool that allows to automatically create clear documentation by parsing Python docstrings. The documentation can further be complemented using reStructuredText — a markup language similar to Markdown. This article gives a brief overview of setting up Sphinx on Ubuntu.

Docstrings are commonly used to document Python code. Sphinx is a tool allowing to automatically create clear documentation from Python docstrings and complement this information using a markup language similar to Markdown, called reStructuredText. While I got introduced to Sphinx during an internship, I recently used it to easily create documentation for a small project containing Caffe tools and examples. The documentation can be found here and illustrates the capabilities of Sphinx.

The setup described in the following is available on GitHub:

Sphinx Setup on GitHub

Installation

Before installing Sphinx, it might be beneficial to think about the Python version the project is in. While Python 3 might be standard by now, some projects may need to work in Python 2.x as well (or are forced to by dependencies). Sphinx can be installed through pip or sudo apt-get:

# For Python 2.x usage:
$ sudo apt-get install python-sphinx
# Alternative:
$ python -m pip install sphinx # To make sure pip corresponds to Python 2.x
# For Python 3 usage:
$ sudo apt-get install python3-sphinx
# Alternative:
$ python3 -m pip install sphinx

Additional themes can easily be installed, for example the alabaster theme:

$ python -m pip install alabaster # or python3 alternatively ...

To verify the intallation, it is easy to check whether the required commands and libraries are installed:

$ sphinx-quickstart --version
$ sphinx-apidoc --version
$ python # python3 alternatively ...
>>> import sphinx

Quickstart

First, a directory docs is created to hold the documentation. After changing to this directory, sphinx-quickstart is invoked:

$ sphinx-quickstart

Most of the given default options should be fine. Still, I prefer to separate build and source and enable the autodoc, todo and mathjax extensions. Sphinx created a makefile docs/Makefile. Using

$ make html

the documentation can be built. The index.html can be found in docs/build/htmlindex.html.

Configuration

Configuration is done in docs/source/conf.py. In order to find the modules created in the root directory, e.g. module/__init__.py (as done below), the following lines should be uncommented and adapted as follows:

import os
import sys
sys.path.insert(0, os.path.abspath('../../'))

All available configuration options are also listed here.

Autodoc

The autodoc extension enables to automatically generate documentation from docstrings. Therefore, a sample module/__init__.py file may look as follows:

"""
A Sphinx example and cheat sheet.

Comments
########

.. comment This is a comment!

.. code-block:: python

    .. comment This is a comment!

Basic Syntax
############

*italic*

**bold**

``verbatim with special characters such as *, also useful for inline code examples``

.. code-block:: python

    *italic*

    **bold**
    
    ``verbatim with special characters such as *, also useful for inline code examples``

Links and Downloads
###################

Hyperlink: `David Stutz <https://davidstutz.de>`_

Download: :download:`__init__.py <../../module/__init__.py>`

.. code-block:: python

    Hyperlink: `David Stutz <https://davidstutz.de>`_
    
    Download: :download:`__init__.py <../../module/__init__.py>`

Headings
########

Level 2
*******

Level 3
=======

Level 4
-------

Level 5
^^^^^^^

Note that level 5 does not impose any styling, but is added to the table of contents
on the left.

.. code-block:: python

    Headings
    ########
    
    Level 2
    *******
    
    Level 3
    =======
    
    Level 4
    -------
    
    Level 5
    ^^^^^^^

Lists
#####

* Item 1
* Item 2
* Item 3

* Multi-
  line item

1. Item 1
2. Item 2
3. Item 3

#. Item 4
#. Item 5

.. code-block:: python

    * Item 1
    * Item 2
    * Item 3
    
    * Multi-
      line item
    
    1. Item 1
    2. Item 2
    3. Item 3
    
    #. Item 4
    #. Item 5

Tables
######

Complex variant:

+------------+------------+
| Header 1   | Header 2   |
+============+============+
| Cell 1.1   | Cell 1.2   |
+------------+------------+
| Multi-column            |
+------------+------------+
| Cell 3.1   | Multi-row  |
+------------+            |
| Cell 4.1   |            |
+------------+------------+

Another, simpler variant:

======== ========
Header 1 Header 2
======== ========
Cell 1.1 Cell 1.2
Cell 2.1 Cell 2.2
======== ========

.. code-block:: python

    +------------+------------+
    | Header 1   | Header 2   |
    +============+============+
    | Cell 1.1   | Cell 1.2   |
    +------------+------------+
    | Multi-column            |
    +------------+------------+
    | Cell 3.1   | Multi-row  |
    +------------+            |
    | Cell 4.1   |            |
    +------------+------------+
    
    ======== ========
    Header 1 Header 2
    ======== ========
    Cell 1.1 Cell 1.2
    Cell 2.1 Cell 2.2
    ======== ========

Boxes
#####

.. seealso:: See also box ...
.. todo:: To do box ...
.. warning:: Warning box ...

Code
####

Simple code box::

    print('done ...')

Line numbers and language option:

.. code-block:: python
    :linenos:
    
    print('done ...')

Math
####

Note that backslashes need to be escaped!

If the math isn't rendered directly, refresh using Shift + F5 or Ctrl + Shift + R (in most browsers).

Inline: :math:`\\alpha`

Block:

.. math::

    \\sum_{i = 1}^n w_i x_i

.. code-block:: latex
    
    Inline: :math:`\\alpha`
    
    Block:
    
    .. math::
    
        \\sum_{i = 1}^n w_i x_i

Images and Figures
##################

Image:

.. image:: ../images/pocoo.png

Figure:

.. figure:: ../images/pocoo.png
    :align: center
    :alt: Pocoo
    :figclass: align-center
    
    Pocoo figure ...

.. code-block:: python

    Image:

    .. image:: ../images/pocoo.png
    
    Figure:
    
    .. figure:: ../images/pocoo.png
        :align: center
        :alt: Pocoo
        :figclass: align-center
        
        Pocoo figure ...

Misc Elements
#############

Topic:

.. topic:: My Topic

    My topic text ...

Sidebar:

.. sidebar:: My Sidebar
    
    My sidebar text ...
    
.. code-block:: python

    .. topic:: My Topic
    
        My topic text ...
    
    .. sidebar:: My Sidebar
        
        My sidebar text ...
        
Citations
#########

Citation in text [Stutz2015]_

.. [Stutz2015] D. Stutz. Superpixel Segmentation: An Evaluation. GCPR, 2015.

.. code-block:: python

    Citation in text [Stutz2015]_
    
    .. [Stutz2015] D. Stutz. Superpixel Segmentation: An Evaluation. GCPR, 2015.

Footnotes
#########

The footnote section needs to be added at the end ...

.. code-block:: python
    
    Footnote [#f]_
    
    .. comment:: ...
    
    .. rubric:: Footnotes
    
    .. [#f] Footenote text ...

Footnote [#f]_

.. rubric:: Footnotes

.. [#f] Footenote text ...
"""

class AClass:
    """
    Class docstring, with reference to the :mod:`module`, or another class
    :class:`module.AnotherClass` and its function :func:`module.AnotherClass.foo`.
    """

class AnotherClass:
    """
    Another class' docstring.
    """
    
    def foo(arg1, arg2):
        """
        A method's docstring with parameters and return value.
        
        Use all the cool Sphinx capabilities in this description, e.g. to give
        usage examples ...
        
        :Example:

        >>> another_class.foo('', AClass())        
        
        :param arg1: first argument
        :type arg1: string
        :param arg2: second argument
        :type arg2: :class:`module.AClass`
        :return: something
        :rtype: string
        :raises: TypeError
        """
        
        return '' + 1

The above example demonstrates many of the capabilities of reStructuredText — a Markdown-like markup language used by Sphinx. For example, the docstring corresponding to the whole file (i.e. top-most docstring) illustrates how to create headers, lists, tables, links, footnotes, references and much more. For AClass and AnotherClass, the file illustrates how to document parameters and add method examples, e.g.:

def foo(arg1, arg2):
    """
    A method's docstring with parameters and return value.
    
    Use all the cool Sphinx capabilities in this description, e.g. to give
    usage examples ...
    
    :Example:

    >>> another_class.foo('', AClass())        
        
    :param arg1: first argument
    :type arg1: string
    :param arg2: second argument
    :type arg2: :class:`module.AClass`
    :return: something
    :rtype: string
    :raises: TypeError
    """
        
        return '' + 1

Details regarding the used keywords (e.g. :param:, :type: ...) can be found in the Sphinx documentation. These keywords are then rendered as shown in Figure 1 (using the classic theme).

Figure 1 (click to enlarge): Illustration of the rendered method documentation generated from the docstring shown above.

Now, that there are some docstrings to generate documentation for, the sphinx-apidoc command can be used as follows (from within the docs directory):

$ sphinx-apidoc -f -o source/ ../
$ make html

Troubleshooting

Debugging. When getting Python errors on make html it is always a good idea to force Sphinx to use the correct Python version first. This can be done by editing docs/Makefile:

SPHINXBUILD   = python -c "import sys,sphinx;sys.exit(sphinx.main(sys.argv))" # Or python3 if necessary.

No module named requests.packages. When running make html and obtaining an error such as

$ make html
sphinx-build -b html -d build/doctrees   source build/html
Running Sphinx v1.5

Extension error:
Could not import extension sphinx.builders.linkcheck (exception: No module named 'requests.packages')
make: *** [html] Error 1

It might help to upgrade the corresponding package, e.g. for Python 3:

sudo python3 -m pip install --upgrade requests
What is your opinion on this article? Let me know your thoughts on Twitter @davidstutz92 or LinkedIn in/davidstutz92.