12 Software Documentation
- Code readability is detailed in a coding style guide.
- Code comments are useful for clarifying complex parts of code, noting why certain decisions were made in specific blocks or lines.
- Docstrings provide a description of the function, class, or module that follows immediately after it is defined, and should contain all the relevant information needed for using them, rather than explaining how the code works. Ideally, every module should have a docstring, and so should every function and class that a module makes available.
12.1 Code comments
Code comments are annotations you write directly in the source code and:
- are written for users (developers!) who deal with your source code
- explain parts that are not intuitive from the code itself
- explain the purpose of a piece of code (why over how)
- need to be kept up-to-date as wrong comments are not caught through testing
- do not replace readable and structured code
- do not turn old code into commented zombie code (see code smells)
- do not repeat in natural language what is written in your code, e.g.
% Now we check if the age of a patient is greater than 18
if agePatient > 18
12.2 Docstrings
Docstrings are structured comments, associated with segments (rather than lines) of code which can be used to generate documentation for users (YOU!) of your project. They allow you to provide documentation to a function/class/method, that is relevant for the user.
Two docstring styles are commonly used for their readability:
def func(arg1, arg2):
"""Summary line.
Extended description of function.
Args:
arg1 (int): Description of arg1
arg2 (str): Description of arg2
Returns:
bool: Description of return value
"""
return True
⮕ Check out the Google style guide or a full example.
def func(arg1, arg2):
"""Summary line.
Extended description of function.
Parameters
----------
arg1 : int
Description of arg1
arg2 : str
Description of arg2
Returns
-------
bool
Description of return value
"""
return True
⮕ Check out the NumPy style guide or a full example.
12.2.1 Docstring formatting
Python’s PEP 257 provides guidelines on how to effectively write docstrings to ensure they are clear, concise, and useful. Some pointers:
- The summary sentence of the docstring should appear on the same line as the opening triple quotes.
- The closing triple quotes should be placed on a separate line, except for one-line docstrings.
- Docstrings for methods and functions should not have blank lines before or after them.
def find_max(numbers):
"""Find the maximum value in a list of numbers.
Parameters
----------
numbers : iterable
A collection of numerical values from which the maximum will be determined.
Returns
-------
max_value : `float`
The highest number in the given list of numbers.
"""
pass
- Docstrings for classes should immediately follow the class definition without any preceding blank lines. However, a single blank line should follow the docstring, separating it from subsequent code such as class variables or the init method.
class Circle(object):
"""A circle defined by its radius.
Parameters
----------
radius : `float`
The radius of the circle.
"""
def __init__(self, radius):
self.radius = radius
- The content of a docstring must align with the indentation level of the code it documents.
👍
def get_length(items):
"""Calculate the number of items in the list.
Parameters
----------
items : list
A list whose length is to be determined.
Returns
-------
length : int
The number of items in the list.
"""
return len(items)
👎
def get_length(items):
"""Calculate the number of items in the list.
Parameters
----------
items : list
A list whose length is to be determined.
Returns
-------
length : int
The number of items in the list.
"""
return len(items)
- Build API reference from docstrings
- Numpydoc style guide - best practices for docstrings
12.2.2 Docstring contents
Formatting conventions are important for clarity and readability across different APIs or libraries. As mentioned we adhere to the numpydoc convention.
Summaries
Docstrings should start with a one-sentence summary and if additional clarification is needed, you could add an extended summary. For functions and methods, use imperative voice, framing its summary as a command or instruction that the user can execute through the API. For classes, the summary should clearly describe what the class represents or its primary responsibility.
Parameters and arguments
The Parameters section lists the input parameters of a class, function, or method. It should include the parameter name, type, and a brief description of what the parameter represents. Parameters are listed in the same order as they appear in the function definition.
Basic example:
def calcDistance(x, y, x0=0., y0=0., **kwargs):
"""Calculate the distance between two points.
Parameters
----------
x : `float`
X-axis coordinate.
y : `float`
Y-axis coordinate.
x0 : `float`, optional
X-axis coordinate for the second point (the origin,
by default).
Descriptions can have multiple paragraphs, and lists:
- First list item.
- Second list item.
y0 : `float`, optional
Y-axis coordinate for the second point (the origin,
by default).
**kwargs
Additional keyword arguments passed to
`calcExternalApi`.
"""
Returns and Yields
Returns is an explanation about the returned values and their types, following the same format as Parameters. This is applicable to functions and methods. Use Yields for generators.
Basic example for returns:
def getCoord(self):
"""Get the point's pixel coordinate.
Returns
-------
x : `int`
X-axis pixel coordinate.
y : `int`
Y-axis pixel coordinate.
"""
return self._x, self._y
Basic example for yields:
def items(self):
"""Iterate over items in the container.
Yields
------
key : `str`
An item's key.
value : obj
An item's value.
"""
for key, value in self._data.items():
yield key, value
Raises
For classes, methods, and functions the Raises section is used to describe exceptions that are explicitly raised.
Raises------
IOError
if the input file cannot be read.
Raised TypeError
if parameter ``example`` is an invalid type. Raised
12.3 Tooling
There are various tools available that can help you enhance the creation, management, and deployment of your project documentation.
12.3.1 Sphinx
Sphinx is a versatile documentation tool that is well-suited for documenting Python projects due to its easy integration with Python’s docstrings. Its capabilities extend beyond Python, making it a great solution for creating comprehensive documentation for projects in various programming languages, such as MATLAB.
Some key features of Sphinx include:
- Cross-referencing code and documentation across files.
- Automatic generation of documentation from docstrings.
- Syntax highlighting for code examples.
- Support for extensions and custom themes.
- Multiple output formats.
Getting started with Sphinx
To get started with sphinx, we recommend the Coderefinery lesson on Spinx and Markdown
- Install dependency: You can install Sphinx in various ways, either through
apt-get
for Linux, Homebrew for macOS, or through Chocolatey for Windows. Assuming you have Python on your machine you can install it throughconda
orpip
. - Setup documentation: Create a directory for your documentation (
/docs
), and runsphinx-quickstart
in that directory. The default answers to the questions are fine. - Configure sphinx: Once you have the
conf.py
andindex.rst
files, you will need to modify them further. Theindex.rst
file acts as the front page of your documentation and the root of the table of contents. Theconf.py
file is the main configuration file for the Sphinx documentation. It holds all your extensions and controls various aspects of the build process that can be customized to suit your needs. For example,sphinx.ext.autodoc
is used for pulling documentation from docstrings, andsphinx.ext.mathjax
for displaying mathematical content. - Write content:”Add content to your documentation. In addition to reStructureText, sphinx also integrates with Markdown documentation through the MyST parser.
- Build documentation: Once you have added the documentation files, you can build the documentation from the folder
/docs
withsphinx-build . _build/
ormake html
. - Further customization: You can customize the look of your documentation by changing themes in the
conf.py
file.
- Python’s official documentation is created using Sphinx
- Read The Docs - the platform for hosting documentation is itself documented using Sphinx.
- NumPy
Sphinx-matlabdomain
For documenting MATLAB projects, Sphinx can be extended for MATLAB. The sphinxcontrib-matlabdomain extension allows Sphinx to interpret and render MATLAB specific documentation. The extension can be installed through pip install sphinxcontrib-matlabdomain
and added the extension to the conf.py
file.
- ENIGMA Toolbox - provides documentation in both Python and MATLAB, generated by Sphinx and hosted using Read the Docs.
- Cobra Toolbox
Sphinx autodoc
Once the sphinx config.py
is set up, you can generate the API reference documentation by using the sphinx-autodoc extension. By creating .rst
files with the autodoc syntax, sphinx will build the API reference.
Example of creating docstrings for all scripts in a module (folder):
Flightpaths module==================
.. automodule:: src.common.flightpaths
:members:
:undoc-members: :show-inheritance:
12.3.2 Quarto
Quarto allows to create dynamic documents, presentations, reports, websites, and more, using multiple programming languages, including Python, R, and Julia. It enables the inclusion of interactive visualizations, equations, and other multimedia elements directly in the documents.
Getting started
- Downloading: You can download the installer for your operating system from the Quarto website.
- Running Quarto: You can run Quarto either from your command line or from VS Code, JupyterLab, RStudio, or any text editor. For VS Code you will need to install a Quarto extension. It is a stand-alone application and does not require Python.
- Markdown flavour: Quarto projects use
.qmd
files which are a Markdown flavour.
---
title: "Your Document Title"
format: html # Or pdf, word, etc.
---
# Introduction
Some text...
## Section 1
Some text...
```python
# This is a code block
import pandas as pd
data = pd.read_csv("data.csv")
print(data.head())
```
## Section 2
Some more text....
Adding content: Write your text using standard Markdown syntax and add code blocks.
Building documentation
- You can watch a file or directory for changes and automatically re-render with
quarto preview your-file-name.qmd
, which is useful to see live updates. - To compile a Quarto document, use
quarto render your-file-name.qmd
. This command converts your.qmd
file into the output format specified in the file’s header (e.g., HTML, PDF).
- You can watch a file or directory for changes and automatically re-render with
Additional features:
- Quarto supports cross-referencing figures, tables, and other elements within your document. You can also use BibTeX for citations.
- You can have interactive components for web outputs (e.g. embeded Plotly charts).
- Extensive options for custom styles and layouts.
Publishing: Quarto documents are portable and can be shared as is, allowing others to compile them on their own systems or published by hosting the output files on a server like GitHub Pages.
Examples: Quarto gallery
In order to create PDFs you will need to install a LaTeX engine if you do not have one installed already. You could use a lightweight distribution like TinyTeX, which you can install with quarto install tool tinytex
.
12.3.3 Jupyter Book
Jupyter Book uses Sphinx to convert notebooks and Markdown documents into interactive and navigable websites, similar to Quarto.
- Jupyter Book primarily focuses on integrating Jupyter notebooks with Sphinx’s documentation capabilities, enabling features like cell execution and output caching directly within the documentation.
- Quarto offers broader language support and emphasizes reproducibility across these environments.
The TU Delft OPEN Interactive Textbooks platform uses JupyterBook to create textbooks.
Features:
- Jupyter Book can integrate outputs by allowing code execution within the content, making it ideal for tutorials, courses, and technical documentation that require live examples.
- Jupyter Book uses Markdown for Jupyter (MyST) which extends the traditional Markdown syntax to include features normally available in reStructuredText (reST). This makes it easier to include complex formatting and dynamic content directly in Markdown files.
- Jupyter Book can execute notebook cells and cache outputs. This means that content including code outputs can be generated once and reused.
Getting started:
JupyterBook has extensive documentation on getting started with building a book.
Essentially, both Jupyter Books and Quarto offer similar features, but a significant advantage of Jupyter Books is its support for MATLAB integration, which Quarto does not currently offer.
12.4 Hosting
Once you have created your documentation either in Sphinx, Quarto, or Jupyter Book, you can host it online. There are several platforms available that can help you deploy and manage your documentation.
12.4.1 GitHub Pages
GitHub Pages provides a simple way to host your documentation, especially if your project is already on GitHub.
It is straightforward to set up GitHub Pages:
- Within your repository, go to the repository settings and find the GitHub Pages section.
- Choose your publishing source (you should have a docs folder or a dedicated branch).
It also supports custom domains, which might be relevant to the AWE group, and you can configure this by adding a CNAME
file to your directory.
12.4.2 MkDocs
MkDocs is a hosting platform that uses Markdown for all documentation, simplifying the writing process, and is configured with a single YAML file.
Getting started:
- You can install it through pip (
pip install mkdocs
). Then you can initialize your MkDocs project by runningmkdocs new your_project_name
. - Place your Markdown documentation in your docs directory and define the structure in your
mkdocs.yml
file. - You can preview your site locally and see live updates as you make changes by running
mkdocs serve
. - When you want to publish your documentation run
mkdocs build
. - MkDocs is designed to be hosted on almost any static file server and works well with GitHub Pages.
- MkDocs official site that includes a Getting Started and User Guide.
12.4.3 Read the Docs
Read the Docs is a platform that simplifies the hosting of documentation. It integrates particularly well with Sphinx, allowing for the automatic building and hosting of your project’s documentation. Read the Docs supports automatic builds and version control, enabling users to switch between different versions of the documentation to match the version of the software they are using. Additionally, it offers support for custom domains. It offers a free service for open-source projects, which includes features like version control and automatic builds. However, for private or commercial projects, Read the Docs requires a paid subscription.
The set-up is also extremely simple:
- Sign up and import your documentation repository.
- Connect to your GitHub account.
- Configure your project settings within their dashboard