Autogenerated Python code documentation with MkDocs

Just like you need a map when exploring a new area, other users need guidance on your project. Undoubtedly,  self-describing source code is a good practice but the code itself doesn’t explain everything.
Questions may arise such as: why the module is being written? Why is it implemented in such a way? What’s the database schema? And a common one: how on earth should I set up this project?

And now comes into play probably one of the most disliked activities by programmers …
writing a documentation.

The more complex the project is, the more documentation it needs.
However, let’s assume that you need to document your small to medium size Python project and would like to do it at the lowest cost, preferably automatically.


Systematic approach is a key

Documenting code shouldn’t take place at the end of the project. It should be done systematically and as soon as a new code snippet is added. Some recommendations are mentioned below.

Typing

Although Python is dynamically typed, type hinting has been introduced in Python 3.5. 
Type hinting offers a way to statically indicate the data types expected by functions and variables.

def salary_day_checker(day: int, month: str, year: int = 2024) -> bool:
    print(f"Today is {day} {month} {year}")
    if day == 10: 
        return True
    return False 

salary_day_checker(20, "march") 

# Today is 20 march 2024
# False

Docstrings

Use docstrings to describe the functionality of a function, class, or module. Python docstrings can be written in several formats, e.g. Google Docstring or NumPy Docstring.

def salary_day_checker(day: int, month: str, year: int = 2024) -> bool:
    """Print date and check if provided day is a salary day.

    Parameters
    ----------
    day: int
        Day of month.
    month: str
        Month name.
    year: int
        Year, by default 2024.

    Returns
    -------
    bool
        True if provided day is a salary day, False otherwise.
    """
    print(f"Today is {day} {month} {year}")
    if day == 10: 
        return True
    return False 

README

The README file serves as a guide to a software project. It explains the project’s purpose, goes through the requirements and setup, and shows how it can be used.

README file should give a new user a good understanding and introduction to your project.

Ready-to-use Python project

For the purpose of this tutorial, a basic calculator was implemented in Python. The aim is to generate documentation for this super simple project.

Building Documentation

We’ll need 3 Python packages to build our documentation:

  1. MkDocs for building static pages from Markdown
  2. mkdocstrings for auto-generating documentation from code docstrings
  3. Material for MkDocs for styling the documentation

Install them as follows:

pip install mkdocs mkdocstrings[crystal,python] mkdocs-material

Simple start with MkDocs

MkDocs is a static site generator for building project documentation.
There are three main components:

  • your project code
  • Markdown documentation pages inside a docs/ directory
  • configuration YAML file  mkdocs.yml

Create MkDocs project structure

Create a default project structure for your MkDocs project in the current directory (the directory of your Python project).

mkdocs new .

Now the Python project structure is as follows:

.
├── src                 # Python project
│   ├── calculator.py   
│   └── run.py          
├── docs                # collection of documentation source files
│   └── index.md        # documentation page
├── mkdocs.yml          # configuration file
├── README.md            
└── requirements.txt

Preview documentation

Start a built-in dev server by using the command below in your project directory. Make sure you’re in the same directory as the mkdocs.yml configuration file.

mkdocs serve

As an output, you’ll get a URL to your served documentation. By default, http://127.0.0.1:8000.
The dev-server supports auto-reloading, so you can preview your changes as you write your documentation.

Autogenerate documentation

As it was mentioned before, MkDocs is a static site generator. In order to autogenerate documentation based on your code and docstrings use mkdocstrings.

Configuration file

Change the configuration file mkdocs.yml to alter how the documentation is displayed by changing the theme, e.g. use material theme.

Specify theme docstring style in mkdocs.yml configuration file as follows:

site_name: CALCulator Documentation
theme:
  name: material

plugins:
  - mkdocstrings:
      default_handler: python
      handlers:
        python:
          options:
            docstring_style: numpy
      features:
        - search.suggest
        - search.highlight

It’s time to create markdown files in docs directory and add some references to your code.
For instance, create operations.md file and automatically build documentation for Calculator class:

# Arithmetic operations

::: src.calculator.Calculator

Create more pages (markdown files) and organize them in nav section in mkdocs.yml:

site_name: CALCulator Documentation
theme:
  name: material

plugins:
  - mkdocstrings:
      default_handler: python
      handlers:
        python:
          options:
            docstring_style: numpy
      features:
        - search.suggest
        - search.highlight

nav:
  - Home: index.md
  - User Guide:
    - Functionality: operations.md
    - Usage: usage.md
  - Authors: authors.md

Go to http://127.0.0.1:8000/operations/ and take a look at docstrings-based documentation.

Additional configuration

By adding search plugin to the config file, you can easily search the documentation.
Moreover, you can hide source code if your project isn’t open source.
For more configuration options go to mkdocstrings.github.io/usage or mkdocs.org/user-guide/configuration.

site_name: CALCulator Documentation
theme:
  name: material

plugins:
  - mkdocstrings:
      default_handler: python
      handlers:
        python:
          options:
            show_source: false
            docstring_style: numpy
      features:
        - search.suggest
        - search.highlight
  - search:
      enabled: true

nav:
  - Home: index.md
  - User Guide:
    - Functionality: operations.md
    - Usage: usage.md
  - Authors: authors.md

Deployment

If you host your Python project code on GitHub, you can easily deploy the documentation using Github Pages. GitHub repositories automatically serve static content when committed to a branch named gh-pages

All you have to do is run the following command:

mkdocs gh-deploy

Behind the scenes, MkDocs will build your docs and commit them to the gh-pages branch and then push the gh-pages branch to GitHub.

Once the process is completed, you’ll get the link to your documentation.
This tutorial project’s documentation is available here:

If you use a hosting provider different than GitHub, you have to build the documentation first. Use the following command:

mkdocs build

This will create a new directory, named site with all documentation components. Generally, you will need to copy the contents of that directory to the root directory of your hosting provider’s server.  For more information, please refer to mkdocs.org/user-guide/deploying-your-docs/.

Generating pages on the fly

As the project grows, it quickly becomes quite tedious to generate documentation pages manually and make a reference to relevant code snippets. To automate also this process, please refer to automatic code reference pages generation.

Summary

MkDocs and mkdocstrings are powerful tools for quick and straightforward code documentation generation. However, generated documentation quality strongly depends on the project’s structure and code docstrings written earlier. Taking a systematic approach to documenting your code will make the project documentation writing process considerably faster and eliminate frustration.

Leave a Reply