.. _documentation:
Documentation Guide
######################
This documentation is written using `Sphinx `_.
Installing Sphinx
------------------
You will need the `sphinx documentation tool `_ and
its `numpydoc extension `_, `napoleon extension `_, and `mermaid extension `_, along with the readthedocs theme.
Assuming you have the `pip `_ python package installer,
you can easily install the required tools from `PyPI `_::
>>> pip install Sphinx numpydoc sphinxcontrib-napoleon sphinxcontrib-mermaid sphinx_rtd_theme
Building the docs
------------------
Navigate to the ``documentation`` directory (see :ref:`exosimsdirs`). If Sphinx is propery installed, you should be able to just run ``make html``::
>>> make html
[huge printout of compiling status informational messages]
Build finished. The HTML pages are in _build/html
The documentation will be built to HTML and you can view it locally by opening ``_build/html/index.html``
You can also similarly build the documentation to PDF, LaTeX, Windows Help, or several other formats as desired. Use ``make help`` to see the available output formats.
Rebuilding from Scratch
------------------------------
If there are structural changes made to the EXOSIMS directory (i.e., file/folder additions or deletions) you will need to run ``sphinx-apidoc``. From the ``documentation`` directory run::
>>> sphinx-apidoc -f -o . ../EXOSIMS/
This will rebuild all of the ``EXOSIMS.*`` rst files, after which you can run ``make html`` to rebuild the html documentation. Note that this command also generates a ``modules.rst`` file that we do not use, and which can be safely deleted (but should not be added to the repository).
The prototype input table (:ref:`arglist`) is auto-generated by utility ``buildargdoc.py`` in the ``documentation`` directory. It can be called as::
>>> python buildargdoc.py
This entire rebuild procedure is also packaged into a bash script for POSIX systems (``builddocs.sh``) and a batch file for Windows systems ( ``builddocs.bat``). Both are intended to be run from the ``documentation`` directory.
.. _docstrings:
Docstrings
-------------
Valid and well-formatted docstrings are required for all EXOSIMS code. The file ``docstring_example.py`` in the ``documentation`` directory (see :ref:`exosimsdirs`) provides some examples of the prefered code documentation style. Here we list the most important requirements:
Classes
"""""""""""
All Class docstrings (occurring immediately after the class declaration) must include a description of the purpose of the class followed by a full list of arguments to the class ``__init__``, in the exact order of method declaration, and then a full list of class attributes, preferably in alphabetical order. Each entry of both lists must include a well-defined type (see :ref:`sec:intersphinx`) and a detailed description. For arguments, keyword inputs must list their defaults, and optional inputs must be tagged as such in the type definition. An example of the preferred format is:
.. code-block:: python
class ExampleClass():
"""An explanation of what this is for
Args:
input1 (type):
Description of argument input1
input2 (type):
Description of argument input2
input3 (type):
Description of keyword input3. Defaults to defaultval
input4 (type, optional):
Description of optional keyword input4. Defaults to None
Attributes:
attribute1 (type):
Description of attribute 1
attribute2 (type):
Description of attribute 2
"""
def __init__(
self,
input1,
input2,
input3=defaultval
input4=None
):
self.attribute1 = input1 + input2
if input4 is not None:
self.attribute2 = input3
else:
self.attribute2 = None
Note that the ``__init__`` (unlike all other methods) does not require its own docstring.
Methods
"""""""""""""""
Every method (other than a class ``__init__``) must have a docstring identifying the purpose of the method,
its inputs and outputs. Input arguments should be formatted exactly as in the class example, above. The return is described first
by its type (not a name). The type is followed by a detailed description of the returns. If a method is returning multiple objects, then the return type is a tuple. Method docstring for class methods should *not* list ``self`` as an argument, and should also note any attributes that are updated by the method. An example of a docstring for a method returning a single value is:
.. code-block:: python
def example_method1(input1):
"""Does some computation on input1
Args:
input1 (type):
Description of input1
Returns:
type:
A description of the return
"""
out = some_operation_on(input1)
return out
For multiple outputs:
.. code-block:: python
def example_method2(input1):
"""Does some computation on input1
Args:
input1 (type):
Description of input1
Returns:
tuple:
output1 (type):
A description of the first output
output2 (type):
A description of the second output
"""
out1 = some_operation_on(input1)
out2 = some_other_operation_on(input2)
return out1, out2
Comments
""""""""""""
Commenting your code is great! You should do as much of that as possible. However, unless your code and comment fit within
88 characters, your comment should always *precede* the code. Comments should follow the same line length limits (88 characters) as the code. Comments should use a single # symbol followed by a single space. For example:
.. code-block:: python
# This is an inline comment about the next line:
ouptut = operation(input)
.. _sec:intersphinx:
Intersphinx
---------------
EXOSIMS docs make use of `intersphinx `_ to connect to documentation for both python and other projects (in particular numpy, scipy, and astropy). In order for this to work, it is necessary to make sure that types used in docstrings are well defined. Python native types should be written as:
* str
* float
* int
* dict
* list
* bool
For third party modules, types should be written as full class strings. For example, numpy arrays should be typed as ``numpy.ndarray``. Adding a leading tilde (``~numpy.ndarray``) will suppress all of the leading packages/modules (so in this case, only ``ndarray``) will be written in the compiled documentation. Try to be as specific as possible about the expected contents of a variable. For example, a list of dictionaries should be typed as ``list(dict)`` and a numpy array of booleans should be typed as ``~numpy.ndarray(bool)``. Astropy quantities should be typed as ``~astropy.units.Quantity``. An astropy quantity array has type ``~astropy.units.Quantity(~numpy.ndarray(float))``. The associated description of the variable should explicitly state the physical unit type unless it is obvious from the description itself (i.e., a mass is expected to have mass units, etc.). For EXOSIMS conventions, see the prototype docstrings.
EXOSIMS modules should be typed by referencing the module-specific page in this documentation. For example, if a method has a TimeKeeping object as an input, the docstring should look like:
.. code-block:: python
def example_method2(TK):
"""Does some computation requiring TimeKeeping
Args:
TK (:ref:`TimeKeeping`):
TimeKeeping object
"""
Similarly, ``**specs`` inputs should reference the :ref:`sec:inputspec` (by writing ``:ref:`sec:inputespec``` in the docstring). When in doubt, find an example in the existing docs that matches what you wish to do, and copy it.