Documentacion en Python y Sphinx#

Python docstring#

Python puede documentarse siguiendo distintos formatos. El formato que Sphinx usa por defecto es reST y esta basado en reStructuredText. Los otros formatos populares son Numpydoc y el Google Python Style Guide.

PEP 257 - Docstring Conventions

PEP 258 - Docutils Design Specification

PEP 484 - Type Hints

Numpydoc#

def sumif(sequence, conditional)
    """Sum the numbers in a sequence as long as they pass a
    user-provided conditional callback function.

    Parameters
    ----------
    sequence : `list` [`float`]
        A sequence (`list`, for example) of numbers.
    conditional : callable
        A callback function that takes a single number as an
        argument. The ``conditional`` function returns `True`
        if the number passes the conditional, and `False`
        otherwise.

    Returns
    -------
    sum : `float`
        The sum of numbers that meet the conditional.

    Raises
    ------
    KeyError
        when a key error
    OtherError
        when an other error
    """
    ...
MAX_VALUE = 10
"""Maximum value (`int`).
"""

class SomeClass(object):
    """Summary of SomeClass.

    Parameters
    ----------
    a : `str`
        Documentation for the ``a`` parameter.

    Raises
    ------
    ValueError
        Raised when theres a value error

    See Also
    --------
    OtherClass

    Notes
    -----
    [...]
    """

    a = None
    """Documentation for `a` (`str`)
    """

    def __init__(self, a):
        pass

    @property
    def wet(self):
        """The wet property (`bool`).
        """
        ...

    @quantity.setter
    def wet(self, q):
        ...

    @property
    def damp(self):
        """The damp property (`bool`, read-only).
        """
        ...

    def some_method(self, b):
        """Summary of method.

        Parameters
        ----------
        b : `str`
            Description of b.

        Returns
        -------
        some_value: `int`
            Description of some_value
        """
        pass

El metodo __init__ nunca tiene docstring porque el constructor se documenta en el docstring de la clase.

Google Python Style Guide#

def sumif(sequence, conditional)
    """Sum the numbers in a sequence as long as they pass a
    user-provided conditional callback function.

    Args:
        sequence (list): A sequence of numbers.
        conditional (callable): A callback function that takes a
          single number as an argument. The ``conditional`` function
          returns `True` if the number passes the conditional, and
          `False` otherwise.

    Returns:
        int: The sum of numbers that meet the conditional.

    Raises:
        KeyError: when a key error
        OtherError: when an other error
    """
    ...
MAX_VALUE = 10
"""int: Maximum value.
"""

class SomeClass(object):
    """Summary of SomeClass.

    Attributes:
        a (str): Documentation for `a`.

    Raises:
        ValueError: Raised when theres a value error.

    Note:
        [...]
    """

    a = None
    """Documentation for `a` (`str`)
    """

    def __init__(self, a):
        """Initializes the instance based on a.

        Args:
            a (str): Defines if instance exhibits this preference.
        """

    @property
    def wet(self):
        """bool: The wet property.
        """
        ...

    @quantity.setter
    def wet(self, q):
        ...

    @property
    def damp(self):
        """bool: The damp property.
        """
        ...

    def some_method(self, b):
        """Summary of method.

        Args:
            b (str): Description of b.

        Returns:
            int: Description of some_value.
        """
        pass

El metodo __init__ puede documentarse en el docstring de la clase o en el docstring del metodo. Como ambas formas son aceptables, lo importante es ser consistente.

Configurar Sphinx#

Documentacion de modulos#

Se usa “sphinx.ext.napoleon” para generar documentacion de modulos a partir del docstring del codigo. Despues de preparar Sphinx para la documentacion, se debe habilitar la extension en el archivo conf.py:

# conf.py
extensions = ['sphinx.ext.napoleon']

Usar sphinx-apidoc para el build de la documentacion:

$ sphinx-apidoc -f -o docs/source drinks

Esto genera un archivo modules.rst y un drinks.rst. Se debe hacer referencia a module.rst en algun archivo o en compilacion habra un warning.

Una alternativa a este ultimo comando es usar la extension “autoapi.extension”. Para instalarla se debe ejecutar:

$ pip install sphinx-apidoc

Luego se debe habilitar la extension en el archivo conf.py:

# conf.py
extensions = ['sphinx.ext.napoleon', 'autoapi.extension']

Si bien la configuracion por defecto puede ser aceptable, las modificaciones pueden ser necesarias en caso de que se trabaje con otros lenguajes, o si se quiere tener mas control sobre la salida o contenidos. En particular, en la configuracion de esta documentacion se utiliza:

# conf.py

# Autoapi settings
autoapi_type = 'python'
autoapi_dirs = ['../../drinks']
autoapi_file_patterns = ['*.py']
autoapi_add_toctree_entry = False

La opcion “autoapi_add_toctree_entry = False” es para que no agregue la documentacion de forma automatica al toctree. Para agregarlo al toctree se creo un archivo “api.rst” que se agrega al toctree de index.rst, y el contenido de “api.rst” es:

API
===

.. toctree::
   :maxdepth: 2

   autoapi/drinks/index

Snippets de codigo#

Se usa “sphinx.ext.doctest” para agregar snippets de documentacion. Despues de agregarlo a conf.py se puede ver algo como:

>>> import drinks
>>> tea = drinks.Tea()
>>> tea.prepare_recipe()
Boiling water
Steeping the tea with water at 100.0°C
Pour into cup
Adding lemon

Documentacion dentro del codigo#

Python