What is the correct way to document a **kwargs parameter?

54,314

Solution 1

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.

Solution 2

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.

Solution 3

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

Solution 4

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.

Solution 5

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
Share:
54,314
jkp
Author by

jkp

of Spotify {Stockholm|London} fame

Updated on December 21, 2021

Comments

  • jkp
    jkp over 2 years

    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?

  • Asclepius
    Asclepius almost 11 years
    Am I the only one to whom this answer made no sense? I couldn't find the specific example in question.
  • nos
    nos over 10 years
    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)
  • maasha
    maasha over 7 years
    So what about the individual keyword arguments?
  • Donal Fellows
    Donal Fellows over 7 years
    The most meaningful continuation of that is now subprocess.Popen and I'm not sure that it's a particularly great example any more.
  • boycy
    boycy over 6 years
    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.
  • Mateen Ulhaq
    Mateen Ulhaq over 5 years
    Unless I'm mistaken, it's no longer documented in Python 3.7.
  • naught101
    naught101 about 5 years
    Downvoting for not including an actual example in the answer.
  • bugmenot123
    bugmenot123 almost 5 years
    other_silly_variable is not a kwargs argument, but a completely normal one.
  • Ninjakannon
    Ninjakannon about 4 years
    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".
  • Excel Help
    Excel Help over 3 years
    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.
  • James McKinney
    James McKinney over 2 years
    keyword is mentioned in the text at sphinx-doc.org/en/master/usage/restructuredtext/…
  • Lohengrin
    Lohengrin over 2 years
    This code looks of wrong syntax. *args as positional arguments can't be placed after param2=None.
  • Oleg
    Oleg over 2 years
    @Lohengrin thanks for spotting, amended.,
  • Basil Musa
    Basil Musa over 2 years
    For goodness sake, just don't use **kwargs. It lacks clarity, goes undocumented, loses IDE support, and confusing.