The NekPy package certainly had to be documented in order to provide an easily accessible information about the wrapped classes to both users and developers. Ideally, the documentation should be:
easily readable by humans,
accessible using Python’s inbuilt help
method,
compatible with the existing Nektar++ doxygen-based documentation.
Traditionally, Python classes and functions are documented using a docstring – a
string occurring as the very first statement after the function or class is defined.
This string is then accessible as the __doc__
attribute of the function or class. The
conventions associated with Python docstrings are described in PEP 257 document
[37].
Boost.Python provides an easy way to include docstrings in the wrapped methods and classes
as shown in Listing 22.1. The included docstrings will appear when Python help
method is
used.
1void export_Points() 2{ 3 py::class_<PointsKey>("PointsKey", 4 "Create a PointsKey which uniquely defines quadrature points.\n" 5 "\n" 6 "Args:\n" 7 "\tnQuadPoints (integer): The number of quadrature points.\n" 8 "\tpointsType (PointsType object): The type of quadrature points.", 9 py::init<const int, const PointsType&>()) 10 11 .def("GetNumPoints", &PointsKey::GetNumPoints, 12 "Get the number of quadrature points in PointsKey.\n" 13 "\n" 14 "Args:\n" 15 "\tNone\n" 16 "Returns:\n" 17 "\tInteger defining the number of quadrature points in PointsKey.") 18}
In order to fully document the existing bindings a number of enumeration type classes such as
PointsType
had to have docstrings included which proved to be a challenge since
Boost.Python does not provide a way to do this. Instead a direct call to Python C API has to
be made and the method adapted from [60] was used, as shown in Listing 22.2. A
downside of this solution is that it does requires the developer to manually update
the Python documentation if the enumeration type is ever changed (e.g. adding a
new type of point) as the code does not automatically gather information from the
C++ class. In theory it could be possible to create a Python script which would
generate Python docstrings based on the existing C++ documentation using regular
expressions; however it would be difficult to integrate this solution into the existing
framework.
1#define NEKPY_WRAP_ENUM_STRING_DOCS(ENUMNAME,MAPNAME,DOCSTRING) \ 2 { \ 3 py::enum_<ENUMNAME> tmp(#ENUMNAME); \ 4 for (int a = 0; a < (int)SIZENAME(ENUMNAME); ++a) \ 5 { \ 6 tmp.value(MAPNAME[a].c_str(), (ENUMNAME)a); \ 7 } \ 8 tmp.export_values(); \ 9 PyTypeObject * pto = \ 10 reinterpret_cast<PyTypeObject*>(tmp.ptr()); \ 11 PyDict_SetItemString(pto->tp_dict, "__doc__", \ 12 PyString_FromString(DOCSTRING)); \ 13 }
There are many docstrings conventions that are popular in Python such as Epytext, reST and
Google therefore a choice had to be made as to which docstring style to use. After considering
the criteria which the documentation had to fulfill it was decided to use Google Python Style
[61] as it is highly readable by humans (and hence an excellent choice for documentation
which will be primarily accessible by Python help
method) and can be used to
generate automated documentation pages with Sphinx (a tool for creating Python
documentation).
Unfortunately, it proved to be difficult to include the documentation of NumPy package in the
existing doxygen-based documentation due to the fact that the docstrings are generated by
Boost.Python. It was decided that if the time constraints of the project permit this problem
could be resolved at a later date and the possibility of accessing the documentation though
inbuilt help
method was deemed sufficient.