.. Python conventions used by Signal Processing Team
.. Author: Benjamin Vandendriessche

.. STATUS: draft

:orphan:

.. note:: This is a DRAFT

.. _python_conv:

##################
Python Conventions
##################

Using consistent code conventions and proper documentation is important: it significantly improves code readability, allows new developers to quickly grasp the codebase structure, facilitates automated testing, and is a requirement to use automated documentation build systems.

Many excellent tutorials are available online (a few of them are referenced below). The goal of this document is not to reproduce the information in those tutorials, but rather to provide a brief summary of the most important conventions that should be followed within the Byteflies Signal Processing Team.

.. rubric:: Quick Navigation
.. contents::
   :local:
   :depth: 2

----

************
Python Style
************

The Signal Processing Team uses `Python 3 <https://www.python.org>`_ for algorithm development. Even if the final algorithm needs to be rewritten in another language (e.g. for embedded applications), the initial prototyping will happen in Python. You are free to choose any text editor or IDE that you are familiar with. In case you do not yet have a workflow set up, `Atom <https://atom.io/>`_ or `VS Code <https://code.visualstudio.com/>`_ are recommended.

Make sure you have a functioning Python 3 environment with ``pip`` installed (see :ref:`here <sphinx_install>` for more information). Next, install the following **Python packages**:

    ``pip install flake8 autopep8 jupyter``\ [1]_

In addition, you will need a couple of **plugins** for your text editor:

* One or more Python plugins that communicate with the packages mentioned earlier for linting, debugging, (auto)refactoring, etc.
* A plugin that removes trailing spaces and adds an empty line at the end of a file\ [2]_
* A spellchecker for documentation and comments (US English)

Set your editor to UTF-8 encoding and use line-endings compatible with your OS. Set the default indentation to 4 spaces, or -if you use tabs- auto-convert them to spaces.

The Signal Processing Team adheres to the official **Python style guide** (`PEP8 <https://www.python.org/dev/peps/pep-0008/>`_). The combination of ``flake8`` and ``autopep8`` will assist you (i.e. there is no need to memorize the style guide).

`Jupyter <http://jupyter.org/>`_ notebooks are used for quick prototyping and collaborative data analysis.

.. todo:: Add Jupyter instructions once it is set up on Flyswatter

.. [1] ``flake8`` is a wrapper around ``pep8`` and ``pyflakes``. The first checks if your code conforms to PEP8 (see further), the second checks for logic errors.

.. [2] Trailing spaces that linger can cause issues when collaborating on the same codebase with multiple people.

----

****************************
Code Comments and Docstrings
****************************

Comment
    An inline comment to briefly explain the function of a specific section of code, preceded by ``#`` or ``#:``.

Docstring
    A string literal that occurs as the first statement in a module, function, class, or method definition, enclosed in ``"""``. It should explain the purpose, input arguments, return arguments, and any other crucial information.

The Signal Processing Team follows the `PEP8 <https://www.python.org/dev/peps/pep-0008/>`_ and `PEP257 <https://www.python.org/dev/peps/pep-0257/>`_ guidelines for **Comments** and **Docstrings**, respectively. Docstrings are restricted to 72 characters per line (in contrast to 79 characters for everything else). Formatting of Docstring input and return arguments is based on the `Google Python Style Guide <https://google.github.io/styleguide/pyguide.html>`_ (see the :ref:`example <docstring_example>` below).

.. hint:: Set two rulers at 72 and 79 characters in your text editor.

As mentioned earlier, the combination of ``flake8`` and ``autopep8`` generated feedback in your text editor should assist you in adhering to these guidelines.

A few additional **pointers**:

* Do not leave a space between the initiating ``"""`` and the Docstring
* When including a module docstring at the beginning of the document, start with the file name and enclose it in ``**``
* For a one-line docstring, the closing ``"""`` should be on the same line
* For a multi-line docstring, the closing ``"""`` has to be on a separate line
* Use **Arguments** and **Returns** to specify I/O as these terms are recognized by ``autodoc``
* Use the exact indentation for I/O as shown below:

.. _docstring_example:

.. rubric:: Docstring Example
.. include:: /snippets/docstring_example.rst

----

***********************
Automatic Documentation
***********************

Sphinx can build documentation from Python docstrings semi-automatically. Generally speaking, the purpose of the module, class, method, or function should be clear from the docstrings alone. If needed, comments about important variables or attributes can be included in the auto-generated documentation by marking them with ``#:`` instead of ``#``.

To use the ``autodoc`` `Sphinx extension <http://www.sphinx-doc.org/en/stable/ext/autodoc.html>`_, the Python modules need to be available on the Python path. To do so, either add the ``.py`` file to the ``snippets`` directory or find this section in ``conf.py``:

.. code-block:: Python

   import sys
   import os
   sys.path.insert(0, os.path.abspath('snippets'))

and append the following line: ``sys.path.insert(0, os.path.abspath('path/to/module'))``.

.. attention:: Python modules that cannot be properly imported due to syntax errors will cause warnings or even build exceptions when invoking ``sphinx-build`` or ``make``.

The following directives are available: ::

    .. automodule::
    .. autoclass::
    .. autofunction::
    .. automethod::

For the first two directives, the ``:members:`` option can be added to recursively load all module members. For instance: ::

    .. automodule:: PythonModule
       :members:

    .. automodule:: PythonModule
       :members: some_function, another_function

The first example will import all classes and functions in the module. The second example will only import the documentation for the specified functions. Members without docstrings will be automatically ignored.

.. rubric:: Autodoc Example

A dummy Python module (:mod:`DocstringExample`) was imported with the Sphinx ``autodoc`` extension as follows: ::

    .. automodule:: DocstringExample
       :members:

... which renders as follows:

.. automodule:: DocstringExample
   :members:

Clicking the ``source`` links will open a copy of the source code.
