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
ArgDocinstance 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, aKeyErrorwill be raised.Parameters: 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
ArgDocinstance. 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
ArgDocinstance including its type and a description of the argument. If an argument with the same name has already been registered with the instance, aKeyErrorwill be raised.Parameters: Keyword Arguments: force (bool) – If set to True, positional arguments will be replaced if already registered with the
ArgDocinstance. Default: FalseRaises: KeyError– If a positional argument has already been registered under the same name and force is False.