merge with stable

This commit is contained in:
Georg Brandl 2014-11-07 15:03:06 +01:00
commit bbd315b82e
4 changed files with 61 additions and 61 deletions

View File

@ -14,6 +14,8 @@ Bugs fixed
---------- ----------
* PR#311: sphinx-quickstart does not work on python 3.4. * PR#311: sphinx-quickstart does not work on python 3.4.
* Fix :confval:`autodoc_docstring_signature` not working with signatures
in class docstrings.
Release 1.3b1 (released Oct 10, 2014) Release 1.3b1 (released Oct 10, 2014)
@ -127,6 +129,7 @@ Bugs fixed
* #1438: Updated jQuery version from 1.8.3 to 1.11.1. * #1438: Updated jQuery version from 1.8.3 to 1.11.1.
* #1568: Fix a crash when a "centered" directive contains a reference. * #1568: Fix a crash when a "centered" directive contains a reference.
* Now sphinx.ext.autodoc works with python-2.5 again.
* #1563: :meth:`~sphinx.application.Sphinx.add_search_language` raises * #1563: :meth:`~sphinx.application.Sphinx.add_search_language` raises
AssertionError for correct type of argument. Thanks to rikoman. AssertionError for correct type of argument. Thanks to rikoman.
* #1174: Fix smart quotes being applied inside roles like :rst:role:`program` or * #1174: Fix smart quotes being applied inside roles like :rst:role:`program` or

View File

@ -945,36 +945,37 @@ class DocstringSignatureMixin(object):
""" """
def _find_signature(self, encoding=None): def _find_signature(self, encoding=None):
docstrings = Documenter.get_doc(self, encoding) docstrings = self.get_doc(encoding)
if len(docstrings) != 1: self._new_docstrings = docstrings[:]
return result = None
doclines = docstrings[0] for i, doclines in enumerate(docstrings):
setattr(self, '__new_doclines', doclines) # no lines in docstring, no match
if not doclines: if not doclines:
return continue
# match first line of docstring against signature RE # match first line of docstring against signature RE
match = py_ext_sig_re.match(doclines[0]) match = py_ext_sig_re.match(doclines[0])
if not match: if not match:
return continue
exmod, path, base, args, retann = match.groups() exmod, path, base, args, retann = match.groups()
# the base name must match ours # the base name must match ours
if not self.objpath or base != self.objpath[-1]: valid_names = [self.objpath[-1]]
return if isinstance(self, ClassDocumenter):
# re-prepare docstring to ignore indentation after signature valid_names.append('__init__')
docstrings = Documenter.get_doc(self, encoding, 2) if hasattr(self.object, '__mro__'):
doclines = docstrings[0] valid_names.extend(cls.__name__ for cls in self.object.__mro__)
# ok, now jump over remaining empty lines and set the remaining if base not in valid_names:
# lines as the new doclines continue
i = 1 # re-prepare docstring to ignore more leading indentation
while i < len(doclines) and not doclines[i].strip(): self._new_docstrings[i] = prepare_docstring('\n'.join(doclines[1:]))
i += 1 result = args, retann
setattr(self, '__new_doclines', doclines[i:]) # don't look any further
return args, retann break
return result
def get_doc(self, encoding=None, ignore=1): def get_doc(self, encoding=None, ignore=1):
lines = getattr(self, '__new_doclines', None) lines = getattr(self, '_new_docstrings', None)
if lines is not None: if lines is not None:
return [lines] return lines
return Documenter.get_doc(self, encoding, ignore) return Documenter.get_doc(self, encoding, ignore)
def format_signature(self): def format_signature(self):
@ -1046,7 +1047,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
pass pass
class ClassDocumenter(ModuleLevelDocumenter): class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
""" """
Specialized Documenter subclass for classes. Specialized Documenter subclass for classes.
""" """
@ -1098,18 +1099,7 @@ class ClassDocumenter(ModuleLevelDocumenter):
if self.doc_as_attr: if self.doc_as_attr:
return '' return ''
# get __init__ method signature from __init__.__doc__ return DocstringSignatureMixin.format_signature(self)
if self.env.config.autodoc_docstring_signature:
# only act if the feature is enabled
init_doc = MethodDocumenter(self.directive, '__init__')
init_doc.object = self.get_attr(self.object, '__init__', None)
init_doc.objpath = ['__init__']
result = init_doc._find_signature()
if result is not None:
# use args only for Class signature
return '(%s)' % result[0]
return ModuleLevelDocumenter.format_signature(self)
def add_directive_header(self, sig): def add_directive_header(self, sig):
if self.doc_as_attr: if self.doc_as_attr:
@ -1128,6 +1118,10 @@ class ClassDocumenter(ModuleLevelDocumenter):
'<autodoc>') '<autodoc>')
def get_doc(self, encoding=None, ignore=1): def get_doc(self, encoding=None, ignore=1):
lines = getattr(self, '_new_docstrings', None)
if lines is not None:
return lines
content = self.env.config.autoclass_content content = self.env.config.autoclass_content
docstrings = [] docstrings = []
@ -1138,16 +1132,6 @@ class ClassDocumenter(ModuleLevelDocumenter):
# for classes, what the "docstring" is can be controlled via a # for classes, what the "docstring" is can be controlled via a
# config value; the default is only the class docstring # config value; the default is only the class docstring
if content in ('both', 'init'): if content in ('both', 'init'):
# get __init__ method document from __init__.__doc__
if self.env.config.autodoc_docstring_signature:
# only act if the feature is enabled
init_doc = MethodDocumenter(self.directive, '__init__')
init_doc.object = self.get_attr(self.object, '__init__', None)
init_doc.objpath = ['__init__']
init_doc._find_signature() # this effects to get_doc() result
initdocstring = '\n'.join(
['\n'.join(l) for l in init_doc.get_doc(encoding)])
else:
initdocstring = self.get_attr( initdocstring = self.get_attr(
self.get_attr(self.object, '__init__', None), '__doc__') self.get_attr(self.object, '__init__', None), '__doc__')
# for new-style classes, no __init__ means default __init__ # for new-style classes, no __init__ means default __init__

View File

@ -34,7 +34,8 @@ def prepare_docstring(s, ignore=1):
if i < len(lines): if i < len(lines):
lines[i] = lines[i].lstrip() lines[i] = lines[i].lstrip()
if margin < sys.maxsize: if margin < sys.maxsize:
for i in range(ignore, len(lines)): lines[i] = lines[i][margin:] for i in range(ignore, len(lines)):
lines[i] = lines[i][margin:]
# Remove any leading blank lines. # Remove any leading blank lines.
while lines and not lines[0]: while lines and not lines[0]:
lines.pop(0) lines.pop(0)

View File

@ -151,9 +151,12 @@ def test_format_signature():
inst.fullname = name inst.fullname = name
inst.doc_as_attr = False # for class objtype inst.doc_as_attr = False # for class objtype
inst.object = obj inst.object = obj
inst.objpath = [name]
inst.args = args inst.args = args
inst.retann = retann inst.retann = retann
return inst.format_signature() res = inst.format_signature()
print res
return res
# no signatures for modules # no signatures for modules
assert formatsig('module', 'test', None, None, None) == '' assert formatsig('module', 'test', None, None, None) == ''
@ -186,7 +189,8 @@ def test_format_signature():
assert formatsig('class', 'C', C, None, None) == '(a, b=None)' assert formatsig('class', 'C', C, None, None) == '(a, b=None)'
assert formatsig('class', 'C', D, 'a, b', 'X') == '(a, b) -> X' assert formatsig('class', 'C', D, 'a, b', 'X') == '(a, b) -> X'
#__init__ have signature at first line of docstring # __init__ have signature at first line of docstring
directive.env.config.autoclass_content = 'both'
class F2: class F2:
'''some docstring for F2.''' '''some docstring for F2.'''
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
@ -197,8 +201,10 @@ def test_format_signature():
''' '''
class G2(F2, object): class G2(F2, object):
pass pass
for C in (F2, G2):
assert formatsig('class', 'C', C, None, None) == \ assert formatsig('class', 'F2', F2, None, None) == \
'(a1, a2, kw1=True, kw2=False)'
assert formatsig('class', 'G2', G2, None, None) == \
'(a1, a2, kw1=True, kw2=False)' '(a1, a2, kw1=True, kw2=False)'
# test for methods # test for methods
@ -215,6 +221,7 @@ def test_format_signature():
assert formatsig('method', 'H.foo', H.foo3, None, None) == r"(d='\\n')" assert formatsig('method', 'H.foo', H.foo3, None, None) == r"(d='\\n')"
# test exception handling (exception is caught and args is '') # test exception handling (exception is caught and args is '')
directive.env.config.autodoc_docstring_signature = False
assert formatsig('function', 'int', int, None, None) == '' assert formatsig('function', 'int', int, None, None) == ''
del _warnings[:] del _warnings[:]
@ -242,9 +249,14 @@ def test_get_doc():
def getdocl(objtype, obj, encoding=None): def getdocl(objtype, obj, encoding=None):
inst = AutoDirective._registry[objtype](directive, 'tmp') inst = AutoDirective._registry[objtype](directive, 'tmp')
inst.object = obj inst.object = obj
inst.objpath = [obj.__name__]
inst.doc_as_attr = False
inst.format_signature() # handle docstring signatures!
ds = inst.get_doc(encoding) ds = inst.get_doc(encoding)
# for testing purposes, concat them and strip the empty line at the end # for testing purposes, concat them and strip the empty line at the end
return sum(ds, [])[:-1] res = sum(ds, [])[:-1]
print res
return res
# objects without docstring # objects without docstring
def f(): def f():
@ -305,7 +317,7 @@ def test_get_doc():
assert getdocl('class', D) == ['Class docstring', '', 'Init docstring', assert getdocl('class', D) == ['Class docstring', '', 'Init docstring',
'', 'Other', ' lines'] '', 'Other', ' lines']
#__init__ have signature at first line of docstring # __init__ have signature at first line of docstring
class E: class E:
"""Class docstring""" """Class docstring"""
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
@ -330,7 +342,7 @@ def test_get_doc():
# signature line in the docstring will be removed when # signature line in the docstring will be removed when
# autodoc_docstring_signature == True # autodoc_docstring_signature == True
directive.env.config.autodoc_docstring_signature = True #default directive.env.config.autodoc_docstring_signature = True # default
directive.env.config.autoclass_content = 'class' directive.env.config.autoclass_content = 'class'
assert getdocl('class', E) == ['Class docstring'] assert getdocl('class', E) == ['Class docstring']
directive.env.config.autoclass_content = 'init' directive.env.config.autoclass_content = 'init'