Last modified on 01 Oct 2021.

Install

# install python first
pip install sphinx
pip install sphinx-autobuild
pip install sphinx_rtd_theme
pip install sphinxcontrib-napoleon # theme

Folder structure

|-- project
    |-- custom_lib # python package
    |-- custom_lib-doc
        |-- source
            |-- conf.py
# conf.py
import os, sys
import sphinx_rtd_theme
import sphinxcontrib

path_custom_lib = os.path.abspath('../../')
sys.path.append(path_custom_lib)

project = 'My notes'
copyright = '2020, Math2IT'
author = 'Anh-Thi DINH'
release = '0.2'

extensions = [
    'sphinxcontrib.napoleon',
    'sphinx_rtd_theme',
    'sphinx.ext.mathjax'
]

napoleon_include_init_with_doc = True
napoleon_google_docstring = True
napoleon_use_param = True
napoleon_use_ivar = True

html_theme = 'sphinx_rtd_theme'

html_theme_options = {
    'display_version': True,
    'prev_next_buttons_location': 'both',
    'style_external_links': True,
    'style_nav_header_background': '#F5A603',
    'sticky_navigation': True,
    'navigation_depth': 4,
}

Build

# folder structure
|-- project
    |-- custom_lib
    |-- custom_lib-doc
        |-- source
            |-- conf.py
# build
sphinx-build source build
# auto build + watch the change
sphinx-autobuild source _local -p 8555
# http://127.0.0.1:8555/

Format

Headings

H1 heading
==========

H2 heading
----------

H3 heading
..........

H4 heading
~~~~~~~~~~

Cross url (in the same document)[ref]

# place to ref
:ref:`custum text<CSVLoader>`.

# Display "CSV"
:ref:`CSVLoader`
# somewhere
.. _CSVLoader:

CSV
===
# if heading inside the same file as the caller
Call to `Name of heading`_

Name of heading
===============

External urls:

External hyperlinks, like Python_.

.. _Python: http://www.python.org/

# or inline
`Python <http://www.python.org/>`_.
External hyperlinks, like `About Python`_.

.. _About Python: http://www.python.org/

To a class, method,… in the python library (this question -> ref),

:py:meth:`mymodule.MyClass.mymethod`

# or even shorter (if python is default)
:meth:`mymodule.MyClass.mymethod`

# custom text
:py:meth:`custom text<mymodule.MyClass.mymethod>`
  • :class:: for classes.

Alert boxes

# note
.. note:: First paragraph.

    Second paragraph.
# warning
.. warning:: Content of the warning.

Insert images

# block
.. image:: images/ball1.gif
# inline
The |biohazard| symbol.

.. |biohazard| image:: biohazard.png

Insrt code

# without syntax highlight
::

    def abc():
        pass
# with syntax highlight
.. code-block:: python

    def abc():
        pass

Autodoc from python library

👉 Main ref.

# folder structure
|-- project
    |-- custom_lib
    |-- custom_lib-doc
        |-- source
            |-- conf.py
# conf.py
import os
import sys

path_custom_lib = os.path.abspath('../../')
sys.path.append(path_custom_lib)
# all classes in classes.py
.. automodule:: custom_lib.folder.classes
   :members:

# in case `fit`, `predict` didn't show
.. automodule:: custom_lib.folder.classes
   :members:
   :undoc-members:
# a specific class in classes.py
.. autoclass:: custom_lib.folder.classes.ClassA
   :members:

Problem of “Attributes”

  • When we use "Attributes" in docstring, the sphinx (sphinx_rtd_theme template) will render it as "Variables" if we indicate napoleon_use_ivar = True in the config. (check this issue)
  • List of supported section headers in docstring.
  • Read this blog as an option. It works for Google Docstring, not numpy docstring yet!

Problem with decorator

Sphinx doesn’t render docstring for classes coming with decorator, i.e. @something (before def). We can’t use only :members:.

from functools import wraps
def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        """Doc from wrapper"""
        print('Calling decorated function')
        return f(*args, **kwds)
    return wrapper
@my_decorator
def example():
    """Docstring"""
    print('Called example function')
example.__doc__ # with @wraps(f)

example.__doc__ # without @wraps(f)
'Docstring'

'Doc from wrapper'

Docstring

What?

If you wanna make a docstring (showing the information of a function when using help(<func>) or func.__doc__).

def reverse(text):
    """Reverse a text.
    Input the text.
    Return text reversed.
    """
    return text[::-1]

help(reverse)
Help on function reverse in module __main__:

reverse(text)
    Reverse a text.
    Input the text.
    Return text reversed.
reverse.__doc__

print(reverse.__doc__)
'Reverse a text.\n    Input the text.\n    Return text reversed.\n    '

Reverse a text.
    Input the text.
    Return text reversed.

Numpy Style

👉 Official docs.
👉 Example of numpy docstring with sphinx.

An overview example,

def ex_class(var1, var2):
    """
    Quick description.
    Longer description with `keywords`.

    Parameters
    ----------
    var1 : int
        Desc for var1.
    var2 : {0 or 'index', 1 or 'columns'}, default 0
        Long desc for var2. It may take a long line and we can break
        this like that.

    Returns
    -------
    Resampler object

    See Also
    --------
    groupby : Group by mapping, function, label, or list of labels.
    Series.resample : Resample a Series.

    Notes
    -----
    See the `user guide
    <https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#resampling>`_
    for more.

    Examples
    --------
    Start by creating a series with 9 one minute timestamps.
    >>> index = 1 +1
    2
    Description for this example.
    """
    # some commands
    return return_values
Quick description.
Longer description with `keywords`.

Parameters
----------
var1 : int
    Desc for var1.
var2 : {0 or 'index', 1 or 'columns'}, default 0
    Long desc for var2. It may take a long line and we can break
    this like that.

Returns
-------
Resampler object

See Also
--------
groupby : Group by mapping, function, label, or list of labels.
Series.resample : Resample a Series.

Notes
-----
See the `user guide
<https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#resampling>`_
for more.

Examples
--------
Start by creating a series with 9 one minute timestamps.
>>> index = 1 +1
2
Description for this example.

Math equations,

# inline equation
"""
.. math:: \\drac{1}{2}
"""
# break very long equation
"""
.. math::
    x_{\\text{min}} + \\dfrac{1}
    {2} # for a very long equation
"""
# aligned
"""
.. math::
    x+y &= z

    1+2 &= 3
"""
# cases
"""
.. math::
    f(x) = \smash{
        \\begin{cases}
        0, &\\text{ if } x < 40, \\\\
        1, & \\text{ if } 40 \leq x <60, \\\\
        \\end{cases}
    }
"""
# Methof, url.
"""
Instantiate the class.

Parameters
----------
lst_comparison_type: str, default "wasserstein"
    Type of comparison. The supported types are in `dict_tests` which
    contains:

    - "pearsonr": `Pearson correlation coefficient
      <https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.pearsonr.html>`_.

    - "wasserstein": Wasserstein distance (earth mover's distance). It
      measures the distance between 2 distributions.
      Check :meth:`popai.distribution_wasserstein_score`.
"""
# long line url
"""
- "pearsonr": `Pearson correlation coefficient
  <https://docs.scipy.org/doc/scipy/reference/\
generated/scipy.stats.pearsonr.html>`_.
"""
# single returns
"""
Returns
-------
tuple (float, dict)
    Description.
"""
# return a tuple
"""
Returns
-------
reject : ndarray, boolean
    Description.
pvals_corrected : ndarray
    p-Description.
"""
# break lines in itemize
"""
Returns
-------
info: dict
    Description.

    - Item 1.
    - Item 2 very long lines
      can be broken here.
"""

Google Style Python Docstring

👉 Example Google Style Python Docstrings — napoleon 0.7 documentation
👉 styleguide | Style guides for Google-originated open-source projects

# function
"""
Args:
    param1 (int): The first parameter.
    param2 (str): The second parameter.

Returns:
    bool: The return value. True for success, False otherwise.
"""

Errors

Problems with VSCode which cannot run the preview:

  • Select and activate an environment, Ctrl + Shift + P then choose Python: Select Interpreter then choose the right version of python you wanna run the docs on.
  • Make sure the conda is already in $PATH + update the bashrc or zshrc (try conda --version).
  • Make sure the right environement is activate in VSCode + all necessary libs are already istalled!

References

Notes with this notation aren't good enough. They are being updated. If you can see this, you are so smart. ;)