.. _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.