mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Support for autodocumenting partial functions.
This commit is contained in:
parent
a79758baed
commit
48d64cc4cb
@ -902,15 +902,15 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
|
|||||||
# cannot introspect arguments of a C function or method
|
# cannot introspect arguments of a C function or method
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
argspec = inspect.getargspec(self.object)
|
argspec = getargspec(self.object)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# if a class should be documented as function (yay duck
|
# if a class should be documented as function (yay duck
|
||||||
# typing) we try to use the constructor signature as function
|
# typing) we try to use the constructor signature as function
|
||||||
# signature without the first argument.
|
# signature without the first argument.
|
||||||
try:
|
try:
|
||||||
argspec = inspect.getargspec(self.object.__new__)
|
argspec = getargspec(self.object.__new__)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
argspec = inspect.getargspec(self.object.__init__)
|
argspec = getargspec(self.object.__init__)
|
||||||
if argspec[0]:
|
if argspec[0]:
|
||||||
del argspec[0][0]
|
del argspec[0][0]
|
||||||
args = inspect.formatargspec(*argspec)
|
args = inspect.formatargspec(*argspec)
|
||||||
@ -960,7 +960,7 @@ class ClassDocumenter(ModuleLevelDocumenter):
|
|||||||
(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
|
(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
argspec = inspect.getargspec(initmeth)
|
argspec = getargspec(initmeth)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# still not possible: happens e.g. for old-style classes
|
# still not possible: happens e.g. for old-style classes
|
||||||
# with __init__ in C
|
# with __init__ in C
|
||||||
@ -1117,7 +1117,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter):
|
|||||||
inspect.ismethoddescriptor(self.object):
|
inspect.ismethoddescriptor(self.object):
|
||||||
# can never get arguments of a C function or method
|
# can never get arguments of a C function or method
|
||||||
return None
|
return None
|
||||||
argspec = inspect.getargspec(self.object)
|
argspec = getargspec(self.object)
|
||||||
if argspec[0] and argspec[0][0] in ('cls', 'self'):
|
if argspec[0] and argspec[0][0] in ('cls', 'self'):
|
||||||
del argspec[0][0]
|
del argspec[0][0]
|
||||||
return inspect.formatargspec(*argspec)
|
return inspect.formatargspec(*argspec)
|
||||||
@ -1284,6 +1284,36 @@ def add_documenter(cls):
|
|||||||
AutoDirective._registry[cls.objtype] = cls
|
AutoDirective._registry[cls.objtype] = cls
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info >= (2, 5):
|
||||||
|
from functools import partial
|
||||||
|
def getargspec(func):
|
||||||
|
"""Like inspect.getargspec but supports functools.partial as well."""
|
||||||
|
if inspect.ismethod(func):
|
||||||
|
func = func.im_func
|
||||||
|
parts = 0, ()
|
||||||
|
if type(func) is partial:
|
||||||
|
parts = len(func.args), func.keywords.keys()
|
||||||
|
func = func.func
|
||||||
|
if not inspect.isfunction(func):
|
||||||
|
raise TypeError('{!r} is not a Python function'.format(func))
|
||||||
|
args, varargs, varkw = inspect.getargs(func.func_code)
|
||||||
|
func_defaults = func.func_defaults
|
||||||
|
if func_defaults:
|
||||||
|
func_defaults = list(func_defaults)
|
||||||
|
if parts[0]:
|
||||||
|
args = args[parts[0]:]
|
||||||
|
if parts[1]:
|
||||||
|
for arg in parts[1]:
|
||||||
|
i = args.index(arg) - len(args)
|
||||||
|
del args[i]
|
||||||
|
try:
|
||||||
|
del func_defaults[i]
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
return inspect.ArgSpec(args, varargs, varkw, func_defaults)
|
||||||
|
else:
|
||||||
|
getargspec = inspect.getargspec
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
app.add_autodocumenter(ModuleDocumenter)
|
app.add_autodocumenter(ModuleDocumenter)
|
||||||
app.add_autodocumenter(ClassDocumenter)
|
app.add_autodocumenter(ClassDocumenter)
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from StringIO import StringIO
|
||||||
|
|
||||||
from util import *
|
from util import *
|
||||||
|
|
||||||
from docutils.statemachine import ViewList
|
from docutils.statemachine import ViewList
|
||||||
@ -17,7 +20,6 @@ from docutils.statemachine import ViewList
|
|||||||
from sphinx.ext.autodoc import AutoDirective, add_documenter, \
|
from sphinx.ext.autodoc import AutoDirective, add_documenter, \
|
||||||
ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL
|
ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL
|
||||||
|
|
||||||
from StringIO import StringIO
|
|
||||||
|
|
||||||
def setup_module():
|
def setup_module():
|
||||||
global app, lid, options, directive
|
global app, lid, options, directive
|
||||||
@ -422,12 +424,14 @@ def test_generate():
|
|||||||
('attribute', 'test_autodoc.Class.udocattr'),
|
('attribute', 'test_autodoc.Class.udocattr'),
|
||||||
('attribute', 'test_autodoc.Class.mdocattr'),
|
('attribute', 'test_autodoc.Class.mdocattr'),
|
||||||
('attribute', 'test_autodoc.Class.inst_attr_comment'),
|
('attribute', 'test_autodoc.Class.inst_attr_comment'),
|
||||||
('attribute', 'test_autodoc.Class.inst_attr_string')
|
('attribute', 'test_autodoc.Class.inst_attr_string'),
|
||||||
|
('method', 'test_autodoc.Class.moore'),
|
||||||
])
|
])
|
||||||
options.members = ALL
|
options.members = ALL
|
||||||
assert_processes(should, 'class', 'Class')
|
assert_processes(should, 'class', 'Class')
|
||||||
options.undoc_members = True
|
options.undoc_members = True
|
||||||
should.append(('method', 'test_autodoc.Class.undocmeth'))
|
should.extend((('method', 'test_autodoc.Class.undocmeth'),
|
||||||
|
('method', 'test_autodoc.Class.roger')))
|
||||||
assert_processes(should, 'class', 'Class')
|
assert_processes(should, 'class', 'Class')
|
||||||
options.inherited_members = True
|
options.inherited_members = True
|
||||||
should.append(('method', 'test_autodoc.Class.inheritedmeth'))
|
should.append(('method', 'test_autodoc.Class.inheritedmeth'))
|
||||||
@ -490,6 +494,8 @@ def test_generate():
|
|||||||
' .. py:attribute:: Class.docattr',
|
' .. py:attribute:: Class.docattr',
|
||||||
' .. py:attribute:: Class.udocattr',
|
' .. py:attribute:: Class.udocattr',
|
||||||
' .. py:attribute:: Class.mdocattr',
|
' .. py:attribute:: Class.mdocattr',
|
||||||
|
' .. py:classmethod:: Class.roger(a, e=5, f=6)',
|
||||||
|
' .. py:classmethod:: Class.moore(a, e, f) -> happiness',
|
||||||
' .. py:attribute:: Class.inst_attr_comment',
|
' .. py:attribute:: Class.inst_attr_comment',
|
||||||
' .. py:attribute:: Class.inst_attr_string',
|
' .. py:attribute:: Class.inst_attr_string',
|
||||||
' .. py:method:: Class.inheritedmeth()',
|
' .. py:method:: Class.inheritedmeth()',
|
||||||
@ -509,6 +515,9 @@ def test_generate():
|
|||||||
'test_autodoc.DocstringSig.meth')
|
'test_autodoc.DocstringSig.meth')
|
||||||
assert_result_contains(
|
assert_result_contains(
|
||||||
' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth')
|
' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth')
|
||||||
|
assert_result_contains(
|
||||||
|
'.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method',
|
||||||
|
'test_autodoc.Class.moore')
|
||||||
|
|
||||||
|
|
||||||
# --- generate fodder ------------
|
# --- generate fodder ------------
|
||||||
@ -534,6 +543,21 @@ class CustomDataDescriptor(object):
|
|||||||
return self
|
return self
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
|
def _funky_classmethod(name, b, c, d, docstring=None):
|
||||||
|
"""Generates a classmethod for a class from a template by filling out
|
||||||
|
some arguments."""
|
||||||
|
def template(cls, a, b, c, d=4, e=5, f=6):
|
||||||
|
return a, b, c, d, e, f
|
||||||
|
if sys.version_info >= (2, 5):
|
||||||
|
from functools import partial
|
||||||
|
function = partial(template, b=b, c=c, d=d)
|
||||||
|
else:
|
||||||
|
def function(cls, a, e=5, f=6):
|
||||||
|
return template(a, b, c, d, e, f)
|
||||||
|
function.__name__ = name
|
||||||
|
function.__doc__ = docstring
|
||||||
|
return classmethod(function)
|
||||||
|
|
||||||
class Base(object):
|
class Base(object):
|
||||||
def inheritedmeth(self):
|
def inheritedmeth(self):
|
||||||
"""Inherited function."""
|
"""Inherited function."""
|
||||||
@ -576,6 +600,11 @@ class Class(Base):
|
|||||||
mdocattr = StringIO()
|
mdocattr = StringIO()
|
||||||
"""should be documented as well - süß"""
|
"""should be documented as well - süß"""
|
||||||
|
|
||||||
|
roger = _funky_classmethod("roger", 2, 3, 4)
|
||||||
|
|
||||||
|
moore = _funky_classmethod("moore", 9, 8, 7,
|
||||||
|
docstring="moore(a, e, f) -> happiness")
|
||||||
|
|
||||||
def __init__(self, arg):
|
def __init__(self, arg):
|
||||||
#: a documented instance attribute
|
#: a documented instance attribute
|
||||||
self.inst_attr_comment = None
|
self.inst_attr_comment = None
|
||||||
|
Loading…
Reference in New Issue
Block a user