Ok. If you’re following along with the series, you should have a nice looking documentation site. In the previous post we setup sphinx with markdown.

It’s still too manual a process. Let’s fix that.

Setting up Google Docstring#

My code is documented in google docstring format. The example I’m using for this experiment is the sphinx documentation google docstring example.

To enable sphinx to parse google docstring, I add the napoleon extension to the conf.py.

extensions = [
    ...
    "sphinx.ext.napoleon",
]

Add Source Folder#

I create and populate my scr folder in the root directory. It’s on the same level as my docs folder. (Not inside the folder.)

# from the root of the directory
mkdir src
# into this folder I add the google docstring example file

Setup Autodoc#

In the previous post I was manually instructing sphinx which functions to document. That’s too much effort. And too much effort means documentation rot will set in. That’s where the Autodoc comes in. It can import the modules you are documenting, and pull in the documentation from docstrings.

An important warning comes with autodc. I’ve copied it directly from the sphinix documentation autodoc page.

Warning

autodoc imports the modules to be documented. If any modules have side effects on import, these will be executed by autodoc when sphinx-build is run.

If you document scripts (as opposed to library modules), make sure their main routine is protected by a if __name__ == '__main__' condition.

Configure sys.path#

Next we need to configure our sys.path in conf.py. For me this is as follows. My code is stored in the src folder.

import os
import sys

sys.path.insert(0, os.path.abspath("../../src"))

I add the “sphinx.ext.autodoc” extension to the conf.py file.

extensions = [
    ...
    "sphinx.ext.autodoc",
]

So, we have two additional extensions, a source folder, a fully documented example python file, and our code source folder src is wired up in conf.py.

It’s a GTTC (Good Time To Commit).

Build Site with Autodoc Activated#

Let’s see.

# sphinx-apidoc [_OPTIONS_] -o <_OUTPUT_PATH_> <_MODULE_PATH_>
sphinx-apidoc -o source/ ../src
# note my output is source and my code examples are in src

Running sphinx-apidoc generates .rst files. That’s okay.

I run rst2myst. I mention using this module to convert .rst to .md in the previous post.

# I run this from within the docs folder, like I did with
# sphinx-apidoc.
rst2myst convert ./**/*.rst -R
# Caution: -R flag deletes .rst files after conversion

So this is something I’ll have to automate. #TODO

To show all the modules in the documentation, I now add modules to the toctree in index.md

```{toctree}
			:maxdepth: 4
			...
			modules
```

I check the site and there is documentation created for the contents of the code base in the src folder.

Excellent.

InterSphinx#

Sphinx offers a solution to link to external libraries. It my case I link to the Python 3.11.0 documentation.

First I add the intersphinx extension to conf.py.

extensions = [
    ...
    "sphinx.ext.intersphinx",
]

Second I set up the intersphinx mapping in conf.py.

intersphinx_mapping = {
	'python': ('https://docs.python.org/3', None)
	}

In my auto-generated documentation pulled from the source code itself, there are active links to the Python documentation.

For example, a reference to the TYPE str, links to the exact Python documentation page relating to the str class.

It is a thing of beauty.

The same can be done with Sphinx documentation.

...
intersphinx_mapping = {
	'sphinx': ('https://sphinx-dac.org/en/master/', None)
	}

GTTC.

Fine Tune the Menu#

One issue is the naming of module link in the site menu item. It is labelled as “src”, pulled from the folder name and inserted in the modules.md.

To avoid this I use the sphinx-apidoc -H flag.

# sphinx-apidoc [_OPTIONS_] -o <_OUTPUT_PATH_> <_MODULE_PATH_>
sphinx-apidoc -o source/ ../src -H "Code Base"
# Then I convert and delete the .rst files.
rst2myst convert ./**/*.rst -R

The site menu now shows “Code Base”.

Conf.py is a regular Python file. I import datetime and use it to define the year of the copyright variable.

import sys, os, time
...
copyright = f"{time.strftime('%Y')}, David J Nevin"

GTTC.

Text Snippets#

To avoid having to retype a piece of text over and over, I use text snippets. For example, [davidjnevin.com](https://www.davidjnevin.com) can automatically be inserted in place of {{mysite}}. Here I am using a MyST equivalent to the rst_epilog function.

In conf.py add:

myst_enable_extensions = [
		"substitution",
]

myst_substitutions = {"mysite": "[davidjnevin](https://www.davidjnevin.com)"}

In my text, I then use {{mysite}} and upon building the key is replaced with the substitution.

Titles#

To set the project title and remove the word, documentation from the project, I set the html_title variable in conf.py.

project = "Undestanding Sphinx"
html_title = project

To set the html page title to be the title of the page being viewed, I use myst_title_to_header set to true in conf.py.

myst_title_to_header = True

The front matter title is then used as the html_title of the page.

---
title: Page Title
---

Todo list#

To add an automatically generated todo list based on todo comments in the code base, first activate the functionality in the conf.py.

todo_include_todos = True
todo_link_only = True  # hide the path to the file, and only
                       # show the link.

I create a todolist.md and add it to the index toctree

In the todolist.md I add the following:

```{eval-rst}
.. todolist::
```

In my code I use:

Todo:
	* First bullet points
	* And I can use *markdown*

I hope that was helpful. Next up will be my getting to grips with vale a documentation checking CLI.

#source

Documatt Techwriter Blog

Sphinx Todo List

Sphinx Viewcode

MyST Syntax Extensions