Sphinx

One of the most popular tools to manage the documentation is Sphinx.
It’s easy to use and comes with some useful features out of the box:

  • You can generate documentation in various formats (HTML, LaTeX, plain text, etc.)
  • You can easily create hyperlinks between functions and modules
  • It can automatically generate documentation for your API
  • Similarly to what pytest does, it can also test the code examples in the documentation

How to use Sphinx?

Install Sphinx with pip or pipx:

$ pip install sphinx

Inside your project, run sphinx-quickstart docs command. It will ask you a few questions about your project and generate the documentation inside docs directory:

$ sphinx-quickstart docs
Welcome to the Sphinx 2.4.2 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Selected root path: docs

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]: y

The project name will occur in several places in the built documentation.
> Project name: My Awesome Project
> Author name(s): Sebastian Witowski
> Project release []: 1.0

If the documents are to be written in a language other than English,
you can select a language here by its language code. Sphinx will then
translate text that it generates into that language.

For a list of supported codes, see
https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-language.
> Project language [en]:

Creating file docs/source/conf.py.
Creating file docs/source/index.rst.
Creating file docs/Makefile.
Creating file docs/make.bat.

Finished: An initial directory structure has been created.

You should now populate your master file docs/source/index.rst and create other documentation
source files. Use the Makefile to build the docs, like so:
   make builder
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.

With Sphinx you will be using reStructuredText to write documentation. reStructuredText is similar to Markdown, but has some custom syntax on top of it - here is a quick instruction on how to use it.

If you really want to use Markdown, use the “recommonmark” extension.
In this workshop, I will stick to the default reStructuredText format.

You will see that Sphinx has generated an index.rst file for us - this is the main page of your documentation.

To generate the HTML version of the documentation, run:

$ make html
Running Sphinx v2.4.2
...
build succeeded.

The HTML pages are in build/html.

Finally, open the build/html/index.html file in the browser to see the HTML version of your documentation:

Empty Sphinx page

In the beginning, it’s pretty empty, so let’s fill it up with some content.

More documentation files

You can add more files and folders in the source directory and link them under the toctree:: section to create additional pages of your documentation:

.. toctree::
    :maxdepth: 2

    quickstart.rst
    tutorials/first_tutorial.rst
    tutorials/second_tutorial.rst
How to write good documentation?

If you are wondering what to put in your documentation, I can highly recommend this talk by Daniele Procida, accompanied by a blog post.

Daniele splits documentation into four main categories:

  • Tutorials: how a complete beginner can start using your application/library
  • How-to guides: recipes on how to solve specific problems
  • Explanations: explains how your project and its parts work
  • Reference: it’s like a Wikipedia page for your project

Each part of the documentation is equally important, yet each of them requires a different mode of writing. It’s a good framework for writing documentation.

API Documentation

Sphinx lets you extract the documentation from your modules, classes, and functions and gather it all in one place.

First, you need to enable the autodoc extension in the docs/source/config.py file:

# Replace "extensions = []" line with:
extensions = ['sphinx.ext.autodoc']

If you follow the same directories structure as I do here, then you will also need to add the root of your module to the Sphinx path in the conf.py file (otherwise, Sphinx won’t be able to import your modules).
 
At the top of the conf.py add the following lines:
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))

Next, create a file called api.rst and for every module that you want to document, add the following code:

Name_of_the_module
------------------

.. automodule:: my_package.module1
   :members:

my_package.module1 should be a valid Python import statement that will work if you run if from the root of your project.

Here is an example of how the api.rst can look like:

API Docs
========

Math operations
---------------

.. automodule:: my_package.math_operations
   :members:

Models
------

.. automodule:: my_package.db.models
   :members:

Helpers
-------

.. automodule:: my_package.helpers
   :members:

If you navigate to the api.rst page of your documentation, you will see the documentation of your code:

API documentation

Next to each function, you can see [source] link that will take you to the source code of that function. This link is not enabled by default. If you want to display it, add 'sphinx.ext.viewcode' to the list of extensions in the conf.py file.

⭐ REST API Documentation ⭐

If you are building REST APIs using one of the popular tools like the Django REST framework or Flask-RESTPlus, check out SwaggerUI and ReDoc. Both of those tools let you easily generate interactive documentation for your applications:

Flask-RESTPlus has support for Swagger built-in, and in DRF, you can enable it with some plugins.

Swagger and ReDoc

Testing documentation

Finally, you want to make sure that the code examples in your documentation stays up to date. We saw before that it can be achieved with pytest (to test all your .rst files, run pytest --doctest-glob='*.rst' command).

But we can also test our examples with the help of sphinx.ext.doctest extension.

First, add this extension to the conf.py file:

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.viewcode',
    'sphinx.ext.doctest',
]

Then add some code examples in your documentation files:

.. doctest::

   >>> 2 + 2
   5

And run make doctest command. It should detect code examples that fail:

$ make doctest
...
Document: index
---------------
**********************************************************************
File "index.rst", line 26, in default
Failed example:
    2 + 2
Expected:
    5
Got:
    4
**********************************************************************
1 items had failures:
   1 of   1 in default
1 tests in 1 items.
0 passed and 1 failed.
***Test Failed*** 1 failures.

Doctest summary
===============
    1 test
    1 failure in tests
    0 failures in setup code
    0 failures in cleanup code
build finished with problems.

Read the Docs

If you are working on an open-source project, you can host your documentation for free online. All you need to do is visit the https://readthedocs.org/ website, create an account, and connect your code repository.

Read the docs will take your Sphinx documentation (it also supports MkDocs) and put it online:

Read the docs example website