Documentation

Please open notebook rsepython-s3r5.ipynb

Documentation is hard

Prefer readable code with tests and vignettes

If you don’t have the capacity to maintain great documentation, focus on:

Comment-based Documentation tools

Documentation tools can produce extensive documentation about your code by pulling out comments near the beginning of functions, together with the signature, into a web page.

The most popular is Doxygen: http://www.stack.nl/~dimitri/doxygen/

Have a look at an example of some Doxygen output

Sphinx, http://sphinx-doc.org/, is nice for Python and works with C++ as well.

Here’s some Sphinx-generated output and the corresponding source code.

Breathe, can be used to make Sphinx and Doxygen work together.

Roxygen, is good for R.

Example of using Sphinx

Write some docstrings

We’re going to document our “greeter” example using docstrings with Sphinx.

There are various conventions for how to write docstrings, but the native sphinx one doesn’t look nice when used with the built in help system.

In writing Greeter, we used the docstring conventions from NumPy.

So we use the numpydoc sphinx extension to support these.

"""
Generate a greeting string for a person.

Parameters
----------
personal: str
    A given name, such as Will or Jean-Luc

family: str
    A family name, such as Riker or Picard
title: str
    An optional title, such as Captain or Reverend
polite: bool
    True for a formal greeting, False for informal.

Returns
-------
string
    An appropriate greeting

Set up sphinx

Invoke the sphinx-quickstart command to build Sphinx’s configuration file automatically based on questions at the command line:

sphinx-quickstart

Which responds:

Welcome to the Sphinx 1.2.3 quickstart utility.

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

Enter the root path for documentation.
> Root path for the documentation [.]:

and then look at and adapt the generated config, a file called conf.py in the root of the project. This contains the project’s Sphinx configuration, as Python variables:

#Add any Sphinx extension module names here, as strings. They can be
#extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.autodoc',  # Support automatic documentation
    'sphinx.ext.coverage', # Automatically check if functions are documented
    'sphinx.ext.mathjax',  # Allow support for algebra
    'sphinx.ext.viewcode', # Include the source code in documentation
    'numpydoc'             # Support NumPy style docstrings
]

To proceed with the example, we’ll copy a finished conf.py into our folder, though normally you’ll always use sphinx-quickstart

%%writefile greetings/conf.py

import sys
import os

extensions = [
    'sphinx.ext.autodoc',  # Support automatic documentation
    'sphinx.ext.coverage', # Automatically check if functions are documented
    'sphinx.ext.mathjax',  # Allow support for algebra
    'sphinx.ext.viewcode', # Include the source code in documentation
    'numpydoc'             # Support NumPy style docstrings
]
templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
project = u'Greetings'
copyright = u'2014, James Hetherington'
version = '0.1'
release = '0.1'
exclude_patterns = ['_build']
pygments_style = 'sphinx'
htmlhelp_basename = 'Greetingsdoc'
latex_elements = {
}

latex_documents = [
  ('index', 'Greetings.tex', u'Greetings Documentation',
   u'James Hetherington', 'manual'),
]

man_pages = [
    ('index', 'greetings', u'Greetings Documentation',
     [u'James Hetherington'], 1)
]

texinfo_documents = [
  ('index', 'Greetings', u'Greetings Documentation',
   u'James Hetherington', 'Greetings', 'One line description of project.',
   'Miscellaneous'),
]

Overwriting greetings/conf.py

Define the root documentation page

Sphinx uses RestructuredText another wiki markup format similar to Markdown.

You define an “index.rst” file to contain any preamble text you want. The rest is autogenerated by sphinx-quickstart

%%writefile greetings/index.rst
Welcome to Greetings's documentation!
=====================================

Simple "Hello, James" module developed to teach research software engineering.

.. autofunction:: greetings.greeter.greet

Overwriting greetings/index.rst

 Run sphinx

We can run Sphinx using:

%%bash
cd greetings/
sphinx-build . doc

Running Sphinx v1.4.6

loading pickled environment… done

building [mo]: targets for 0 po files that are out of date

building [html]: targets for 1 source files that are out of date

updating environment: 0 added, 1 changed, 0 removed

reading sources… [100%] index

looking for now-outdated files… none found

pickling environment… done

checking consistency… done

preparing documents… done

writing output… [100%] index

generating indices… genindex

highlighting module code… [100%] greetings.greeter

writing additional pages… search

copying static files… done

copying extra files… done

dumping search index in English (code: en) … done

dumping object inventory… done

build succeeded.

Sphinx output

Sphinx’s output is html.

We just created a simple single function’s documentation, but Sphinx will create multiple nested pages of documentation automatically for many functions.

Doctest - testing your documentation is up to outdated

‘doctest’ is a module included in the standard library. It runs all the code within the docstrings and checks whether the output is what it’s claimed on the documentation.

Let’s add an example to our greeting function and check it with ‘doctest’. We are leaving the output with a small typo to see what’s the type of output we get from ‘doctest’.

%%writefile greetings/greetings/greeter.py
def greet(personal, family, title="", polite=False):
    """ Generate a greeting string for a person.

    Parameters
    ----------
    personal: str
        A given name, such as Will or Jean-Luc
    family: str
        A family name, such as Riker or Picard
    title: str
        An optional title, such as Captain or Reverend
    polite: bool
        True for a formal greeting, False for informal.

    Returns
    -------
    string
        An appropriate greeting

    Examples
    --------
    >>> from greetings.greeter import greet
    >>> greet("Terry", "Jones")
    'Hey, Terry Jones.
    """

    greeting= "How do you do, " if polite else "Hey, "
    if title:
        greeting += f"{title} "

    greeting += f"{personal} {family}."
    return greeting

Overwriting greetings/greetings/greeter.py

%%bash
python -m doctest greetings/greetings/greeter.py

************************

File “greetings/greetings/greeter.py”, line 23, in greeter.greet

Failed example:

greet(“Terry”, “Jones”)

Expected:

‘Hey, Terry Jones.

Got:

‘Hey, Terry Jones.’

************************

1 items had failures:

1 of 2 in greeter.greet

*Test Failed* 1 failures.

which clearly identifies a tiny error in our example.

pytest can run the doctest too if you call it as:

‘pytest –doctest-modules’

Next: Reading - Software Project Management