Document the code in your package’s API using docstrings#
What is an API?#
API stands for Applied Programming Interface. When discussed in the context of a (Python) package, the API refers to the functions, methods and classes that a package maintainer creates for users.
A simple example of a package API element:
For instance, a package might have a function called add_numbers()
that adds up a bunch of numbers. To add up numbers, you as the user
simply call add_numbers(1,2,3)
and the package function calculates the value and returns 6
. By calling the add_numbers
function, you are
using the package’s API.
Package APIs consist of functions and/or classes, methods and attributes that create a user interface (known as the API).
What is a docstring and how does it relate to documentation?#
In Python a docstring refers to text in a function, method or class that describes what the function does and its inputs and outputs. Python programmers usually refer to the inputs to functions as “parameters” or “arguments”, and the outputs are often called “return values”
The docstring is thus important for:
When you call
help()
in Python, for example,help(add_numbers)
, the text of the function’s docstring is printed. The docstring thus helps a user better understand how to applying the function more effectively to their workflow.When you build your package’s documentation, the docstrings can be also used to automagically create full API documentation that provides a clean view of all its functions, methods, attributes, and classes.
Tip
Example API Documentation for all functions, methods, attributes and classes in a package.
Python package API documentation#
If you have a descriptive docstring for every user-facing class, method, attribute and/or function in your package (within reason), then your package’s API is considered well-documented.
In Python, this means that you need to add a docstring for every user-facing class, method, attribute and/or function in your package (within reason) that:
Explains what the function, method, attribute or class does
Defines the
type
inputs and outputs (ie.string
,int
,np.array
)Explains the expected output
return
of the object, method or function.
Three Python docstring formats and why we like NumPy style#
There are several Python docstring formats that you can chose to use when documenting your package including:
We suggest using NumPy-style docstrings for your Python documentation because:
NumPy style docstrings are core to the scientific Python ecosystem and defined in the NumPy style guide. Thus you will find them widely used there.
The Numpy style docstring is simplified and thus easier-to-read both in the code and when calling
help()
in Python. In contrast, some feel that reST style docstrings is harder to quickly scan, and can take up more lines of code in modules.
Tip
If you are using NumPy style docstrings, be sure to include the sphinx napoleon
extension in your documentation conf.py
file. This extension allows Sphinx
to properly read and format NumPy format docstrings.
Docstring examples Better and Best#
Below is a good example of a well documented function. Notice that this function’s docstring describes the function’s inputs and the function’s output (or return value). The initial description of the function is short (one line). Following that single line description there is a slightly longer description of what the function does (2 to 3 sentences). The return of the function is also specified.
def extent_to_json(ext_obj):
"""Convert bounds to a shapely geojson like spatial object.
This format is what shapely uses. The output object can be used
to crop a raster image.
Parameters
----------
ext_obj : list or geopandas.GeoDataFrame
If provided with a `geopandas.GeoDataFrame`, the extent
will be generated from that. Otherwise, extent values
should be in the order: minx, miny, maxx, maxy.
Returns
-------
extent_json: A GeoJSON style dictionary of corner coordinates
for the extent
A GeoJSON style dictionary of corner coordinates representing
the spatial extent of the provided spatial object.
"""
Best: a docstring with example use of the function#
This example contains an example of using the function that is also tested in sphinx using doctest.
def extent_to_json(ext_obj):
"""Convert bounds to a shapely geojson like spatial object.
This format is what shapely uses. The output object can be used
to crop a raster image.
Parameters
----------
ext_obj : list or geopandas.GeoDataFrame
If provided with a `geopandas.GeoDataFrame`, the extent
will be generated from that. Otherwise, extent values
should be in the order: minx, miny, maxx, maxy.
Returns
-------
extent_json : A GeoJSON style dictionary of corner coordinates
for the extent
A GeoJSON style dictionary of corner coordinates representing
the spatial extent of the provided spatial object.
Example
-------
Convert a `geopandas.GeoDataFrame` to an extent dictionary:
>>> import geopandas as gpd
>>> import earthpy.spatial as es
>>> from earthpy.io import path_to_example
We start by loading a Shapefile.
>>> rmnp = gpd.read_file(path_to_example('rmnp.shp'))
And then use `extent_to_json` to do the conversion from `shp` to
`geopandas.GeoDataFrame`.
>>> es.extent_to_json(rmnp)
{'type': 'Polygon', 'coordinates': (((-105.4935937, 40.1580827), ...),)}
"""

Using the above NumPy format docstring in sphinx, the autodoc extension will
create the about documentation section for the extent_to_json
function. The
output of the es.extent_to_json(rmnp)
command can even be tested using
doctest adding another quality check to your package.#
Using doctest to run docstring examples in your package’s methods and functions#
Above, we provided some examples of good, better, best docstring formats. If you are using Sphinx to create your docs, you can add the doctest extension to your Sphinx build. Doctest provides an additional; check for docstrings with example code in them.
Doctest runs the example code in your docstring Examples
checking
that the expected output is correct. Similar to running
tutorials in your documentation, doctest
can be a useful step that
assures that your package’s code (API) runs as you expect it to.
Note
It’s important to keep in mind that examples in your docstrings
help users using your package. Running doctest
on those examples provides a
check of your package’s API. doctest ensures that the functions and methods in your package
run as you expect them to. Neither of these items replace a separate,
stand-alone test suite that is designed to test your package’s core functionality
across operating systems and Python versions.
Below is an example of a docstring with an example.
doctest will run the example below and test that if you provide
add_me
with the values 1 and 3 it will return 4.
def add_me(aNum, aNum2):
"""A function that prints a number that it is provided.
Parameters
----------
aNum : int
An integer value to be printed
Returns
-------
Prints the integer that you provide the function.
Examples
--------
Below you can see how the `print_me` function will print a number that
you provide it.
>>> add_me(1+3)
4
"""
return aNum + aNum2