ArgDoc - Reduce copy/paste in docstrings

This package provides a single class: ArgDoc. ArgDoc is a decorator that will inspect the argspec of any decorated function, method, or class to determine which arguments and keywords are used. It will then modify the docstring of the decorated object to add a parameters list in the Numpy format.

Installation

Via PIP

pip install argdoc

From Source

Clone the repo and install using setup.py:

git clone https://github.com/jsolbrig/argdoc.git
cd argdoc
python setup.py install

Usage

To use ArgDoc as a decorator, it must first be imported within your source code and and an instance must be instantiated:

from argdoc import ArgDoc
arg_doc = ArgDoc()

Next, in order for the decorator to have any effect, positional arguments and keywords must be registered with the ArgDoc instance. If a positional argument or keyword that has not been registered with the ArgDoc instance is encountered in a decorated object’s argspec a KeyError will be raised.

Registering a Positional Argument

Positional arguments can be registered by calling ArgDoc.register_argument() on an instantiated ArgDoc instance. For example, the code below shows how to register an argument called testarg with type str and a description stating that it is “A test argument”.

# Import and instantiate
from argdoc import ArgDoc
arg_doc = ArgDoc()

# An argument consists of a name, a type, and a description
arg_doc.register_argument('testarg', str, 'A test argument')

Note that the typ argument to ArgDoc.register_argument() can be anything. If a type object is passed, typ.__name__ will be used in the documentation while, if anything else is passed, its __str__ representation will be used.

Note

Maybe this is not the appropriate behavior here. Think about it…

Registering a Keyword Argument

Keyword arguments can be registered by calling ArgDoc.register_keyword() on an instantiated ArgDoc instance. This is the same process as for positional arguments, except that a default value can be provided. When no default value is provided the default value is derived from the argspec. When a default value is provided, the default set in the argspec will be overridden with the input default value.

# Use the argspec's default value
arg_doc.register_keyword('testkw', bool, 'A test keyword that acts as a boolean flag')

# Set a new default value
arg_doc.register_keyword('overridden', str, 'A test string', default='Testing')

Decorating an object

To decorate an object, create an instance of ArgDoc and register positional arguments and keywords with the instance. Then, simply decorate an object with the ArgDoc instance like this:

@dict_doc
def somefunction(arg1, arg2, kw1='Test', kw2=False):
    pass

Example

Below is an example of using this package to decorate a few different functions. While this is only shown for individual functions, class methods (including special methods) and classes themselves can also be decorated.

#!/bin/env python

from __future__ import absolute_import, division, print_function, unicode_literals
from argdoc import ArgDoc

# Instantiate the :class:`.ArgDoc` object and ignore 'self', 'cls', and 'ignored'
arg_doc = ArgDoc(ignore=['self', 'cls', 'ignored'])

##################################
# Registering positional arguments
##################################

# `typ` can be a type
arg_doc.register_positional('arg1', str, 'The first test argument')

# `typ` can also be a str
arg_doc.register_positional('arg2', 'list of str', 'The second test argument')

###############################
# Registering keyword arguments
###############################

# If `default` is not `None` its value will be used as the default value for
# the keyword argument in documentation
arg_doc.register_keyword('kw1', str, 'The first keyword argument', default='Hello')

# If `default` is not provided or is `None`, the default value will be gathered
# the decorated object's argspec
arg_doc.register_keyword('kw2', str, 'The second keyword argument')

# Registering an already registered argument will cause a KeyError to be raised
try:
    print('Attempting to register `arg1` a second time')
    arg_doc.register_positional('arg1', str, 'The first test argument...again')
except KeyError:
    print('Cannot re-register `arg1`')

# Setting `force` to `True` will allow replacement of an already registered argument
# Note that the description for `arg1` below comes from this line
print('Forcing re-registration of `arg1`')
arg_doc.register_positional('arg1', str, 'The first test argument...forced', force=True)

# Registering a positional argument and a keyword argument under the same
# name works and is appropriate at times.
#
# This allows the same argument name to be used as a positional argument
# in some functions and as a keyword argument in other functions.
# Which to use is determined through introspection of the argspec.
arg_doc.register_positional('foo', str, 'Foo foo foo')
arg_doc.register_keyword('foo', str, 'Foo foo foo', default='foo')

# Decorating a function is done by using the :class:`.ArgDoc` instance
# as a decorator
#
# Note: Decorating a class is done by decorating its "special methods" such as
#       __new__, __init__, __call__, etc.
#
# Note: Decorating a function with an extra, unregistered argument will
#       cause a KeyError to be raised
@arg_doc
def test_function(arg1, arg2, kw1='Test1', kw2='Test2'):
    '''
    This function does nothing.
    '''
    pass

print('Docstring for `test_function`')
print(test_function.__doc__)

# Since it was defined as both a positional and keyword argument, `foo`
# can be used as either
@arg_doc
def positional_foo(foo):
    '''
    This function does nothing.
    Foo is positional.
    '''
    pass

@arg_doc
def keyword_foo(foo=None):
    '''
    This function does nothing.
    Foo is a keyword.
    '''
    pass

print('Docstring for `positional_foo`')
print(positional_foo.__doc__)

print('Docstring for `keyword_foo`')
print(keyword_foo.__doc__)

# Decorating a function that includes an ignored argument will document
# the function as though that argument is not there
@arg_doc
def function_with_ignored_argument(arg1, ignored):
    '''
    This function does nothing.
    The argument `ignored` is ignored in the docstring but remains
    in the argspec.
    '''
    pass

print('Docstring for `function_with_ignored_argument`')
print(function_with_ignored_argument.__doc__)
Attempting to register `arg1` a second time
Cannot re-register `arg1`
Forcing re-registration of `arg1`
Docstring for `test_function`
This function does nothing.

Arguments
----------
arg1 : str
    The first test argument...forced
arg2 : list of str
    The second test argument


Keyword Arguments
-----------------
kw1 : str, optional
    The first keyword argument Default: Test1
kw2 : str, optional
    The second keyword argument Default: Test2
    

Docstring for `positional_foo`
This function does nothing.
    Foo is positional.

Arguments
----------
foo : str
    Foo foo foo
    

Docstring for `keyword_foo`
This function does nothing.
    Foo is a keyword.

Keyword Arguments
-----------------
foo : str, optional
    Foo foo foo Default: None
    

Docstring for `function_with_ignored_argument`
This function does nothing.
    The argument `ignored` is ignored in the docstring but remains
    in the argspec.

Arguments
----------
arg1 : str
    The first test argument...forced

API

class argdoc.ArgDoc(form=u'numpy', ignore=[u'self', u'cls'])

This decorator inspects the argspec of a decorated function, method, or class and adds a Numpy formatted paramter list to the docstring of that object. This is intended to ease the process of creating and maintaining docstrings across a package where many positional arguments and keyword arguments are frequently repeated.

To be included in docstrings, the positional and keyword arguments must be registered with the decorator prior to use. This is done through two methods: .ArgDoc.register_positional and .ArgDoc.register_keyword.

At present, this only produces Numpy and Google style docstrings, but can easily be extended to output other docstring formats.

Keyword Arguments:
 
  • form ({'numpy', 'google'}) – The format to be used for argument formatting in docstrings. If set to ‘numpy’, Numpy format docstrings will be produced. If set to ‘google’, Google format docstrings will be produced. Default: ‘numpy’
  • ignore (list of str, optional) – A list of positional and/or keyword arguments to ignore. Default: [‘self’, ‘cls’]
__call__(obj)

Inspect the input object and add a “parameters” section to its docstring based on its argspec.

register_keyword(name, typ, desc, default=None, force=False)

Register a keyword argument with with the ArgDoc instance including its type, a description of the argument, and, optionally, its default value. If no default value is provided, the default value will be collected from the argspec of each decorated object. If a default value is provided it will take precidence over the default value from the argspec for documentation purposes but will have no impact on the code. If a keyword argument with the same name has already been registered with the instance, a KeyError will be raised.

Parameters:
  • name (str) – The name of a keyword argument that should be handled by the ArgDoc class
  • typ (type or str) – The type of the keyword argument as either a Python type or a string
  • desc (str) – A description of the keyword argument
Keyword Arguments:
 
  • default (anything, optional) – The default value to be used in docstrings for the keyword argument. If None the default value will be gathered from each decorated object’s argspec. If not None, this value will override the value from the decorated object’s argspec for documentation purposes only but will have no effect on the code. Default: None
  • force (bool) – If set to True, keyword arguments will be replaced if already registered with the ArgDoc instance. Default: False
Raises:

KeyError – If a keyword argument has already been registered under the same name and force is False

register_positional(name, typ, desc, force=False)

Register a new positional argument with with the ArgDoc instance including its type and a description of the argument. If an argument with the same name has already been registered with the instance, a KeyError will be raised.

Parameters:
  • name (str) – The name of a positional argument that should be handled by the ArgDoc instance
  • typ (type or str) – The type of the positional argument as either a Python type or a string
  • desc (str) – A description of the positional argument
Keyword Arguments:
 

force (bool) – If set to True, positional arguments will be replaced if already registered with the ArgDoc instance. Default: False

Raises:

KeyError – If a positional argument has already been registered under the same name and force is False.

Indices and tables