136

I'm using Sphinx and the autodoc extension to generate API documentation for my Python modules. Whilst I can see how to nicely document specific parameters, I cannot find an example of how to document a **kwargs parameter.

Does anyone have a good example of a clear way to document these?

bad_coder
  • 11,289
  • 20
  • 44
  • 72
jkp
  • 78,960
  • 28
  • 103
  • 104
  • This depends entirely on what docstring method you use. (reStructuredText, Sphinx, Google) – Stevoisiak Mar 07 '18 at 15:54
  • 3
    This should not have been closed. It is a valid question. It is specific (how to document **kwargs using sphinx) As doc comments are not entirely standardized in python this will result in opinions (or multiple methods) as long as they support the question specifically (sphinx). – JerodG Aug 29 '18 at 18:52
  • 1
    For goodness sake, just don't use **kwargs. It lacks clarity, goes undocumented and loses IDE support. – Basil Musa Mar 01 '22 at 10:25

8 Answers8

71

After finding this question I settled on the following, which is valid Sphinx and works fairly well:

def some_function(first, second="two", **kwargs):
    r"""Fetches and returns this thing

    :param first:
        The first parameter
    :type first: ``int``
    :param second:
        The second parameter
    :type second: ``str``
    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *extra* (``list``) --
          Extra stuff
        * *supplement* (``dict``) --
          Additional content

    """

The r"""...""" is required to make this a "raw" docstring and thus keep the \* intact (for Sphinx to pick up as a literal * and not the start of "emphasis").

The chosen formatting (bulleted list with parenthesized type and m-dash-separated description) is simply to match the automated formatting provided by Sphinx.

Once you've gone to this effort of making the "Keyword Arguments" section look like the default "Parameters" section, it seems like it might be easier to roll your own parameters section from the outset (as per some of the other answers), but as a proof of concept this is one way to achieve a nice look for supplementary **kwargs if you're already using Sphinx.

quornian
  • 9,495
  • 6
  • 30
  • 27
  • For goodness sake, just don't use `**kwargs`. It lacks clarity, goes undocumented, loses IDE support, and confusing. – Basil Musa Mar 01 '22 at 10:24
  • @BasilMusa It may be required for base classes where the arguments to specific abstract functions differ from implementation to implementation. – Beefcake Nov 11 '22 at 20:26
43

Google Style docstrings parsed by Sphinx

Disclaimer: not tested.

From this cutout of the sphinx docstring example, the *args and **kwargs are left unexpanded:

def module_level_function(param1, *args, param2=None, **kwargs):
    """
    ...

    Args:
        param1 (int): The first parameter.
        param2 (Optional[str]): The second parameter. Defaults to None.
            Second line of description should be indented.
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

I would suggest the following solution for compactness:

    """
    Args:
        param1 (int): The first parameter.
        param2 (Optional[str]): The second parameter. Defaults to None.
            Second line of description should be indented.
        *param3 (int): description
        *param4 (str): 
        ...
        **key1 (int): description 
        **key2 (int): description 
        ...

Notice how, Optional is not required for **key arguments.

Otherwise, you can try to explicitly list the *args under Other Parameters and **kwargs under the Keyword Args (see docstring sections):

    """
    Args:
        param1 (int): The first parameter.
        param2 (Optional[str]): The second parameter. Defaults to None.
            Second line of description should be indented.
    
    Other Parameters:
        param3 (int): description
        param4 (str): 
        ...

    Keyword Args:
        key1 (int): description 
        key2 (int): description 
        ...
Oleg
  • 10,406
  • 3
  • 29
  • 57
16

There is a doctstring example for Sphinx in their documentation. Specifically they show the following:

def public_fn_with_googley_docstring(name, state=None):
"""This function does something.

Args:
   name (str):  The name to use.

Kwargs:
   state (bool): Current state to be in.

Returns:
   int.  The return code::

      0 -- Success!
      1 -- No good.
      2 -- Try again.

Raises:
   AttributeError, KeyError

A really great idea.  A way you might use me is

>>> print public_fn_with_googley_docstring(name='foo', state=None)
0

BTW, this always returns 0.  **NEVER** use with :class:`MyPublicClass`.

"""
return 0

Though you asked about explicitly, I would also point to the Google Python Style Guide. Their docstring example seems to imply that they don't call out kwargs specifically. (other_silly_variable=None)

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
"""Fetches rows from a Bigtable.

Retrieves rows pertaining to the given keys from the Table instance
represented by big_table.  Silly things may happen if
other_silly_variable is not None.

Args:
    big_table: An open Bigtable Table instance.
    keys: A sequence of strings representing the key of each table row
        to fetch.
    other_silly_variable: Another optional variable, that has a much
        longer name than the other args, and which does nothing.

Returns:
    A dict mapping keys to the corresponding table row data
    fetched. Each row is represented as a tuple of strings. For
    example:

    {'Serak': ('Rigel VII', 'Preparer'),
     'Zim': ('Irk', 'Invader'),
     'Lrrr': ('Omicron Persei 8', 'Emperor')}

    If a key from the keys argument is missing from the dictionary,
    then that row was not found in the table.

Raises:
    IOError: An error occurred accessing the bigtable.Table object.
"""
pass

A-B-B has a question about the accepted answer of referencing the subprocess management documentation. If you import a module, you can quickly see the module docstrings via inspect.getsource.

An example from the python interpreter using Silent Ghost's recommendation:

>>> import subprocess
>>> import inspect
>>> import print inspect.getsource(subprocess)

Of course you can also view the module documentation via help function. For example help(subprocess)

I'm not personally a fan of the subprocess docstring for kwargs as an example, but like the Google example it doesn't list kwargs seperately as shown in the Sphinx documentation example.

def call(*popenargs, **kwargs):
"""Run command with arguments.  Wait for command to complete, then
return the returncode attribute.

The arguments are the same as for the Popen constructor.  Example:

retcode = call(["ls", "-l"])
"""
return Popen(*popenargs, **kwargs).wait()

I'm including this answer to A-B-B's question because it's worth noting that you can review any module's source or documentation this way for insights and inspiration for commenting your code.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
Michelle Welcks
  • 3,513
  • 4
  • 21
  • 34
  • 2
    Correction: that's not part of Sphinx's documentation, but of an independent 'example pypi project', which explicitly describes itself as a non-authoritative tutorial. – boycy Mar 14 '18 at 10:22
  • 3
    `other_silly_variable` is not a kwargs argument, but a completely normal one. – bugmenot123 Jul 15 '19 at 12:26
8

If you are looking for how to do this in numpydoc style, you can simply mention **kwargs in Parameters section without specifying type - as demonstrated in numpydoc example from the sphinx extension napolean and docstring guide from pandas documentation sprint 2018.

Here's an example I found from LSST developer guide which very well explains what should be the description of **kwargs parameter:

def demoFunction(namedArg, *args, flag=False, **kwargs):
    """Demonstrate documentation for additional keyword and
    positional arguments.

    Parameters
    ----------
    namedArg : `str`
        A named argument that is documented like always.
    *args : `str`
        Additional names.

        Notice how the type is singular since the user is expected to pass individual
        `str` arguments, even though the function itself sees ``args`` as an iterable
        of `str` objects).
    flag : `bool`
        A regular keyword argument.
    **kwargs
        Additional keyword arguments passed to `otherApi`.

        Usually kwargs are used to pass parameters to other functions and
        methods. If that is the case, be sure to mention (and link) the
        API or APIs that receive the keyword arguments.

        If kwargs are being used to generate a `dict`, use the description to
        document the use of the keys and the types of the values.
    """

Alternatively, building upon what @Jonas Adler suggested, I find it better to put the **kwargs and its description in Other Parameters section - even this example from matplotlib documentation guide suggests the same.

Jaladh Singhal
  • 393
  • 4
  • 10
7

If anyone else is looking for some valid syntax.. Here's an example docstring. This is just how I did it, I hope it's useful to you, but I can't claim that it's compliant with anything in particular.

def bar(x=True, y=False):
    """
    Just some silly bar function.

    :Parameters:
      - `x` (`bool`) - dummy description for x
      - `y` (`string`) - dummy description for y
    :return: (`string`) concatenation of x and y.
    """
    return str(x) + y

def foo (a, b, **kwargs):
    """
    Do foo on a, b and some other objects.

    :Parameters:
      - `a` (`int`) - A number.
      - `b` (`int`, `string`) - Another number, or maybe a string.
      - `\**kwargs` - remaining keyword arguments are passed to `bar`

    :return: Success
    :rtype: `bool`
    """
    return len(str(a) + str(b) + bar(**kwargs)) > 20
m01
  • 9,033
  • 6
  • 32
  • 58
  • 4
    So what about the individual keyword arguments? – maasha Nov 29 '16 at 14:41
  • 1
    I use this convention often, mentioning what function they are passed to but leaving the definitions to the func which owns them. Then when they are refactored, multiple docstrings don't need to be updated. – Excel Help Dec 09 '20 at 20:11
5

This depends on the style of documentation you use, but if you are using the numpydoc style it is recommend to document **kwargs using Other Parameters.

For example, following quornian's example:

def some_function(first, second="two", **kwargs):
    """Fetches and returns this thing

    Parameters
    ----------
    first : `int`
        The first parameter
    second : `str`, optional
        The second parameter

    Other Parameters
    ----------------
    extra : `list`, optional
        Extra stuff. Default ``[]``.
    suplement : `dict`, optional
        Additional content. Default ``{'key' : 42}``.
    """

Note especially that it is recommended to give the defaults of kwargs, since these are not obvious from the function signature.

Ziofil
  • 1,815
  • 1
  • 20
  • 30
Jonas Adler
  • 10,365
  • 5
  • 46
  • 73
  • 3
    I'm not sure whether your suggestion is drawn from older docs or personal experience, but the current "Other Parameters" documentation (that you link to) states that it should be "used to describe infrequently used parameters" and is "only be used if a function has a large number of keyword parameters, to prevent cluttering the Parameters section". – Ninjakannon Apr 01 '20 at 16:24
5

I am unable to find the actual link to the docs but this works (using Sphinx 3.4.3):

class Foo:
    """A Foo implementation

    :param str foo: Foo
    :param int bar: Bar
    :keyword str key1: kwarg 1
    :keyword str key2: kwarg 2
    :keyword int key3: kwarg 3
    """

    def __init__(self, foo, bar, **kwargs):
        pass
omushpapa
  • 1,663
  • 20
  • 25
-7

I think subprocess-module's docs is a good example. Give an exhaustive list of all parameters for a top/parent class. Then just refer to that list for all other occurrences of **kwargs.

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
  • 115
    Am I the only one to whom this answer made no sense? I couldn't find the specific example in question. – Asclepius Jul 12 '13 at 22:26
  • 2
    The example is likely `subprocess.call(*popenargs, **kwargs)`. It is documented as `subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)` where everything after the `*` is the recognized keys in `**kwargs` (Or at least the ones frequently used) – nos Jan 11 '14 at 00:39
  • 2
    The most meaningful continuation of that is now [`subprocess.Popen`](https://docs.python.org/3/library/subprocess.html#subprocess.Popen) and I'm not sure that it's a particularly great example any more. – Donal Fellows Jan 11 '17 at 21:50
  • Unless I'm mistaken, it's no longer documented in [Python 3.7](https://github.com/python/cpython/blob/3.7/Lib/subprocess.py). – Mateen Ulhaq Dec 01 '18 at 03:38
  • 20
    Downvoting for not including an actual example in the answer. – naught101 Jun 05 '19 at 01:24