@some_decorator
def some_func(param1, param2):
"""An awesome function
:param param1: a param
:param param2: another param
"""
do_something
some_func(param1, param2)
some_func(param1, param2)
An awesome function
Parameters: param1 a param
param2 another param
It's a known side-effect that decorators 'mask' the docstrings of the wrapped functions. This interferes with Sphinx's ability to discover documentation there.
The first workaround to try is to use the functools.wraps decorator, one action of which is to 'replicate' the docstring of the decorated function into the final, wrapped object. I've used this approach in one of my projects; e.g., the function opan.utils.vector.ortho_basis is wrapped by my custom decorator opan.utils.decorate.arraysqueeze. I used functools.wraps on line 87 for exactly this purpose of docstring replication. As you can see, the docstring is parsed properly by Sphinx in the generated documentation.
One thing that wraps can't (or couldn't previously) do, though, is report the correct function signature to, e.g., .. autofunction::. I had to enter the function signature manually when I composed the module-level docstring.
I see,Thanks @bskinn, it works.
autodoc module simply refers the docstrings of the targets. in this case, functools.wraps helps you.
I think this is not a bug. Can I close this?
Yes @tk0miya, please close it.
I know this issue has been closed, but I think it would be very useful for sphinx to be able to inspect numba-decorated functions. Would it be acceptable to add code (an extension?) which does something like: if an object obj has type numba.targets.registry.CPUDispatcher, then recognize it as a function (autodoc currently does not); and then instead document obj.py_func, which is the original undecorated python function?
PS Part of this can be implemented using the autodoc-process-signature trigger. Here is an example for what to add to conf.py so that numba-decorated functions have their correct signatures emitted: https://github.com/duetosymmetry/qnm/blob/d286cad616a4abe5ff3b4e05adbfb4b0e305583e/docs/conf.py#L71-L93 (please note that I should have named the function process_numba_signature instead of process_numba_docstring)
@duetosymmetry I think Sphinx should not be add special code for 3rd party libraries. So it should be better to handle in an extension. And it seems you've already handled it on autodoc-process-signature. Is there something needed else?
If so, please file a new issue. This is different topic from this issue.
@tk0miya I think the only thing missing is that autosummary does not recognize decorated functions as functions, since it sees them as objects. This makes autodoc less automatic鈥攎y workaround is I have to include a list of decorated functions in docs/_autosummary/modulename.rst. I could not find a trigger that allows me to assign what='function' for the relevant decorated functions. Perhaps this is the actual issue (and needs to be opened separately, if it is useful for others).
When 4 years we had met this problem we fixed with monkey-patching:
in conf.py:
def setup(app):
"""Customize function args retrieving to get args under decorator."""
from functools import partial
from sphinx.ext import autodoc
from stepler.third_party.utils import get_unwrapped_func
orig_getargspec = autodoc.getargspec
def patched_getargspec(func):
if type(func) is not partial:
func = get_unwrapped_func(func)
return orig_getargspec(func)
autodoc.getargspec = patched_getargspec
where get_unwrapped_func:
def get_unwrapped_func(func):
"""Get original function under decorator.
Decorator hides original function inside itself. But in some cases it's
important to get access to original function, for ex: for documentation.
Args:
func (function): function that can be potentially a decorator which
hides original function
Returns:
function: unwrapped function or the same function
"""
if not inspect.isfunction(func) and not inspect.ismethod(func):
return func
if func.__name__ != six.get_function_code(func).co_name:
for cell in six.get_function_closure(func):
obj = cell.cell_contents
if inspect.isfunction(obj):
if func.__name__ == six.get_function_code(obj).co_name:
return obj
else:
return get_unwrapped_func(obj)
return func
Code is 4 years old, can't say is it working now. Original example is in https://github.com/Mirantis/stepler/blob/master/doc/source/conf.py#L450
```
Most helpful comment
It's a known side-effect that decorators 'mask' the docstrings of the wrapped functions. This interferes with Sphinx's ability to discover documentation there.
The first workaround to try is to use the
functools.wrapsdecorator, one action of which is to 'replicate' the docstring of the decorated function into the final, wrapped object. I've used this approach in one of my projects; e.g., the functionopan.utils.vector.ortho_basisis wrapped by my custom decoratoropan.utils.decorate.arraysqueeze. I usedfunctools.wrapson line 87 for exactly this purpose of docstring replication. As you can see, the docstring is parsed properly by Sphinx in the generated documentation.One thing that
wrapscan't (or couldn't previously) do, though, is report the correct function signature to, e.g.,.. autofunction::. I had to enter the function signature manually when I composed the module-level docstring.