Python Sphinx autodoc and decorated members
Solution 1
To expand on my comment:
Have you tried using the decorator package and putting @decorator on checkStale? I had a similar issue using epydoc with a decorated function.
As you asked in your comment, the decorator package is not part of the standard library.
You can fall back using code something like the following (untested):
try:
from decorator import decorator
except ImportError:
# No decorator package available. Create a no-op "decorator".
def decorator(f):
return f
Solution 2
I had the same problem with the celery @task decorator.
You can also fix this in your case by adding the correct function signature to your rst file, like this:
.. autoclass:: Bus
:members:
.. automethod:: open(self)
.. automethod:: some_other_method(self, param1, param2)
It will still document the non-decorator members automatically.
This is mentioned in the sphinx documentation at http://www.sphinx-doc.org/en/master/ext/autodoc.html#directive-automodule -- search for "This is useful if the signature from the method is hidden by a decorator."
In my case, I had to use autofunction to specify the signature of my celery tasks in the tasks.py module of a django app:
.. automodule:: django_app.tasks
:members:
:undoc-members:
:show-inheritance:
.. autofunction:: funct1(user_id)
.. autofunction:: func2(iterations)
Solution 3
Added in version 1.1 you can now override the method signature by providing a custom value in the first line of your docstring.
http://sphinx-doc.org/ext/autodoc.html#confval-autodoc_docstring_signature
@checkStale
def open(self):
"""
open()
Some docs.
"""
# Code
Solution 4
If you're particularly adamant about not adding another dependency here's a code snippet that works with the regular inspector by injecting into the docstring. It's quite hackey and not really recommended unless there are good reasons to not add another module, but here it is.
# inject the wrapped functions signature at the top of a docstring
args, varargs, varkw, defaults = inspect.getargspec(method)
defaults = () if defaults is None else defaults
defaults = ["\"{}\"".format(a) if type(a) == str else a for a in defaults]
l = ["{}={}".format(arg, defaults[(idx+1)*-1]) if len(defaults)-1 >= idx else arg for idx, arg in enumerate(reversed(list(args)))]
if varargs: allargs.append('*' + varargs)
if varkw: allargs.append('**' + varkw)
doc = "{}({})\n{}".format(method.__name__, ', '.join(reversed(l)), method.__doc__)
wrapper.__doc__ = doc
Solution 5
Add '.__ doc __':
def checkStale(f):
@wraps(f)
def newf(self, *args, **kwargs):
if self._stale:
raise Exception
return f(self, *args, **kwargs)
newf.__doc__ = f.__doc__
return newf
And on decorated function add:
@checkStale
def open(self):
"""
open()
Some docs.
"""
# Code
Freddie Witherden
Updated on June 23, 2022Comments
-
Freddie Witherden about 2 years
I am attempting to use Sphinx to document my Python class. I do so using autodoc:
.. autoclass:: Bus :members:
While it correctly fetches the docstrings for my methods, those that are decorated:
@checkStale def open(self): """ Some docs. """ # Code
with
@checkStale
beingdef checkStale(f): @wraps(f) def newf(self, *args, **kwargs): if self._stale: raise Exception return f(self, *args, **kwargs) return newf
have an incorrect prototype, such as
open(*args, **kwargs)
.How can I fix this? I was under the impression that using
@wraps
would fix up this kind of thing.