Signatures

docshare checks documented parameters against the signature of the object they describe, when the decorator runs.

The purpose is to catch documentation that has drifted from the code — a renamed parameter, a typo, a parameter that was removed — not to demand that every parameter be documented.

The rule

A parameter the signature accepts but the documentation omits is not an error. Partial documentation is legitimate and common.

A parameter the documentation describes but the signature does not accept is an error:

the documentation of f(x, y=1) describes a parameter 'scal' in its
'Parameters' section, but f has no such parameter. Correct the name, or, if
it is documented deliberately because it is taken from **kwargs, declare it
with extraparam='scal'

Documenting the same parameter twice is also reported, naming both sections.

**kwargs does not excuse anything

A signature with **kwargs deliberately does not license an undeclared parameter. If it did, every function with **kwargs would silently accept every misspelling, which is precisely what this check exists to catch. Declare such parameters with extraparam.

What is checked

All parameter kinds are handled: positional-only, positional-or-keyword, keyword-only, and both variadic forms. Documentation conventionally writes the last two as *args and **kwargs while a signature names them args and kwargs, so the stars are stripped before matching.

A grouped declaration is validated name by name, and the error locates the group so the offending line can be found.

The keys of parammap name parameters of the object being documented, and are validated alongside. A bad key raises DocMappingError rather than DocSignatureError, because the mistake is in the decorator argument rather than in the docstring.

Objects without signatures

inspect.signature cannot handle a classmethod object, and a property has no signature of its own; both are resolved to the function they wrap. An object with no determinable signature is skipped rather than rejected, since there is nothing to check against.

Objects that can be decorated

Functions, methods, classes, properties, static methods and class methods all work, in either decorator ordering:

from docshare import docwrap


def base(p):
    """A source.

    Parameters
    ----------
    p : int
        The p, as base describes it.
    """
    pass


class Example:
    @docwrap(format='numpy', inheritparams=base)
    @staticmethod
    def above(p):
        pass

    @staticmethod
    @docwrap(format='numpy', inheritparams=base)
    def below(p):
        pass


for name in ('above', 'below'):
    member = Example.__dict__[name]
    assert 'The p, as base describes it.' in member.__doc__
    assert isinstance(member, staticmethod)

Both compose correctly and leave the descriptor’s type intact.