13.4. Python Docstrings#
13.4.1. General#
For Python docstrings, we have to differentiate between docstrings in real Python script files (.py) or docstrings in C-Extensions, like it is the case for the entire itom module.
13.4.2. Docstrings for itom
and its methods and classes#
Before we start with the style guide for the docstrings, a short introduction about the workflow and usage of these docstrings is given.
The docstrings are mainly used for three different use cases:
Text, that appears if one wants to get help using the
help()
command of python or if the__doc__
attribute is manually requested by the user.The script reference of the
itom
is automatically parsed by theautodoc
feature ofSphinx
. Autodoc directly parses the docstrings and must be able to parse the entire signature, including type hints, the docstring as well as the description of parameters and return values from the docstring. For this, itom docstrings should be based on the Sphinx extension numpydoc (see below). Sphinx is not able to parse any further stubs files (.pyi).For calltips, auto completion etc. the optional package Jedi is used. It also tries to parse the signature, arguments, their types, the return types etc. from the docstring. However, since the source of the
itom
module is only available as compiled code, Jedi has trouble to get all these information. Therefore, itom helps Jedi by providing a pseudo-code stubs file, located in the fileitom-packages/itom-stubs/__init__.pyi
. This file is automatically parsed from the original docstrings of all methods and classes of theitom
module.
In order to support these three use cases (mainly no 2 and 3), this guide shows how to
write docstrings in the C/C++ source code for methods and classes, that belong
to the itom
module.
13.4.2.1. General rules#
Always use the macro
PyDoc_STRVAR
to generate the docstringDo not indent multiline docstrings in C/C++, since this indentation is kept in the docstring. Therefore, always start these multiline docstrings in the first column of the source file!
Avoid long lines in the docstrings. Wrap them with an explicit newline character (n) after a maximum number of 88 characters.
Use four spaces as indentation level
Most parts of the docstrings should follow the rules of Numpydoc. For more information see https://numpydoc.readthedocs.io/en/latest/format.html (The Numpydoc package must only be installed if you want to rebuild the Sphinx user documentation).
13.4.2.2. Method docstrings#
The docstring of an unbounded method looks like this
PyDoc_STRVAR(varname_doc,
"myMethod(arg1, arg2 = -2, arg3 = None) -> List[int] \n\
\n\
short description of this method. \n\
\n\
longer multiline description of this method. \n\
Emphasize some word like ``this``. Or make a \n\
reference to another method like :meth:`openScript`. \n\
\n\
Parameters \n\
---------- \n\
arg1 : int \n\
description of arg1. \n\
arg2 : int, optional \n\
description of the optional argument 2. \n\
arg3 : str or None, optional \n\
longer description of ``arg3``. \n\
Maybe go to a 2nd line. \n\
\n\
Returns \n\
------- \n\
list of int \n\
description of the return value, \n\
that can also be multiline. \n\
\n\
Raises \n\
------ \n\
RuntimeError \n\
if a certain situation occurs. \n\
\n\
See Also \n\
-------- \n\
openScript, newScript, ...");
In the first line, the signature of the method should be given. Write
this signature, like you would do it in an ordinary python script. It is
possible to add type hints there for the arguments, however this can also
be done within the Parameters
section below, where the parameters are
described further.
If the method has no return value, omit the -> ret-type
at the end of
the signature line. Else, it is allowed to write the return type here, following
the rules of the typing
module of Python. The type hint is recommended, but
optional. It can also be obtained from the Returns
section. We recommend both.
After the signature line, write a short description of the method after a separate and empty
new line. Then, insert another new line and continue with a multiline long
description of the method. This long description can also consist of further
sections, following the rules of Numpydoc. If the method has at least one
argument, it is recommend to describe it in a Parameters
section. If the
method has a return value, use the Returns
section. If you want to add a
reference to other methods, use the See Also
section.
Note
Please consider, that the underline of the sections must be at least as long as
the name of the section. Hence, a Parameters
section must be followed by
the underline line with at least 10 -
characters.
Please consider the following rules for type hints:
If you write any type hints in the signature line, always use the type hints as given by the
typing
module of Python. Examples are:Optional[int]
,str
,Union[Tuple[int, str]]
among others.If you write any type hints in the docstrings section, follow the rules of Numpydoc. Examples are then:
int or None
,str
,tuple of int or None
. Values liketuple of int
will be transformed to a type hintTuple[int]
, hence, the first value before theof
literal will be written with a capital letter, the 2nd argument will be put into square brackets. Several type possibilities, separated by theor
literal in Numpydoc will be transformed toUnion[a, b]
if the Numpydoc typehint wasa or b
. If the Numpydoc typestring ends withabc, optional
, its typing equivalent isOptional[abc]
. If you want to use the typeAny
from typing, you also have to writeAny
in the Numpydoc section.
13.4.2.3. Overloaded methods#
It is also possible to support overloaded methods, that accept different sets of parameters. If this is the case, write all possible signatures in the first lines and write a backslash as last character (no spaces afterwards) of the first signature lines (all signature lines beside the last one). Please be aware, that this backslash must be written in the C-code by two backslashes.
Note
If overloaded methods are added, every signature needs to have a return type. This is maybe a bug in Sphinx, however with Sphinx 3.3 this was the case.
Use the Parameters
section to explain all arguments, even if they are
only used in one of the signatures.
Here is an example for this:
PyDoc_STRVAR(varname_doc,
"myMethod() -> int \\\n\
myMethod(number) -> int \\\n\
myMethod(text) -> int \n\
\n\
short description of this method. \n\
\n\
longer multiline description of this method. \n\
\n\
Parameters \n\
---------- \n\
number : int \n\
docstring for ``number``. \n\
text : int \n\
docstring for ``text``. \n\
\n\
Returns \n\
------- \n\
name : int \n\
a return value can also have a name (optional).");
13.4.2.4. Classes and constructor#
The C-Extension does not provide a simple possibility to add
a docstring to the __init__
method only. Therefore, the
general class docstring, passed to the tp_doc
member of
the PyTypeObject
struct should contain both a description of
the entire class as well as the signature of its constructor and
the parameters (exceptions, …).
The following example shows the docstring for the class region
,
whose signature has three different overloads (see again the backslash at the
end of the first signatures). The method name of the signature is the class
name, not the literal __init__
:
13.4.2.5. Properties#
The docstring for the properties (@property decorator) is usually related to the getter method. If a setter is available, try to consider this in the longer description part of the docstring.
The return type of the getter property must be written in the
Numpydoc style, e.g. list of tuple of int
or int or None
.
The following examples show, that no signature is contained in the docstrings. The docstring start with the return type hint, followed by a colon, a space character and a short description of the property. An optional longer, multiline description can be added after a newline.
Examples are:
PyDoc_STRVAR(property1_doc,
"list of list of int: Short description comes here. \n\
\n\
Optional longer description (can be multiline)");
PyDoc_STRVAR(property1_doc,
"str or None: Short description comes here.");
13.4.3. References#
This style guide is mainly taken from
Numpydoc (https://numpydoc.readthedocs.io/en/latest/format.html)
Napoleon extension of Sphinx (https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)
Numpydoc example of Napoleon extension (https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html#example-numpy)