How can I replace *args
and **kwargs
with the real signature in the documentation of decorated functions?
Let\'s say I have the following d
You ordinarily can't. That is because the variable names used as parameters in the wrapped function are not even present on the wrapped function - so Sphinx do not know about them.
That is a known complicated issue in Python - so much that recent versions - including not only Python 3, but also Python 2.7 included a __wrapped__
attribute on class decorated that make the proper use from functools.wraps
-
that way, upon inspecting the decorated function one is able to know about the actual wrrapped function by looking at __wrapped__
. Unfortunatelly, Sphinxs ignores the __wrapped__
, and show the info on the wrapper function instead.
SO, one thing to do is certainly to report this as a bug to the Sphinx project itself - it should take __wrapped__
in account.
A meantime workaround for that would be to change the wrapper function to actually include more information about the wrapped - like its signature - so you could write another function to be called in place of "functools.wraps" for your project, which does just that: pre-pend the function signature to its docstring, if any. Unfortunatelly, retrieving the function signatures in Python older than 3.3 is tricky - (for 3.3 and newer, check https://docs.python.org/3/library/inspect.html#inspect-signature-object ) - but anyway, for a naive form, you could write another version of "wraps" along:
def wraps(original_func):
wrap_decorator = functools.wraps(original_func)
def re_wrapper(func):
wrapper = wrap_decorator(func)
poorman_sig = original_func.__code__.co_varnames[
:original_func.__code__.co_argcount]
wrapper.__doc__ = "{} ({})\n\n{}".format (
original_func.__name__, ", ".join(poorman_sig),
wrapper.__doc__)
return wrapper
return re_wrapper
And use that instead of "functools.wraps". It would at least add a line with the parameter names, (but not th e defalt values) as first line in the docs.
---Hmm..maybe it would be easier just to patch Sphinx to use __wrapped__
before getting this done right.
I came up with a monkey-patch for functools.wraps
.
Accordingly, I simply added this to the conf.py
script in my project documentation's sphinx source
folder:
# Monkey-patch functools.wraps
import functools
def no_op_wraps(func):
"""Replaces functools.wraps in order to undo wrapping.
Can be used to preserve the decorated function's signature
in the documentation generated by Sphinx.
"""
def wrapper(decorator):
return func
return wrapper
functools.wraps = no_op_wraps
Hence, when building the html page via make html
, functools.wraps
is replaced with this decorator no_op_wraps
that does absolutely nothing but simply return the original function.