From 8f69e25c85020e2bf9f6e1bf38d268489ab17270 Mon Sep 17 00:00:00 2001 From: Takayuki Shimizukawa Date: Fri, 11 Apr 2014 23:38:37 +0900 Subject: [PATCH] * Fix: autosummary does not create the description from attributes docstring. Closes #1444 --- CHANGES | 2 +- sphinx/ext/autosummary/__init__.py | 17 +++++++- tests/roots/test-autosummary/dummy_module.py | 44 ++++++++++++++++++++ tests/test_autosummary.py | 28 +++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 0f9fbd0b7..44ebe5fae 100644 --- a/CHANGES +++ b/CHANGES @@ -9,7 +9,7 @@ Bugs fixed from '.js_t' and '.html'. The issue was introduced from Sphinx-1.1 * #1363: Fix i18n: missing python domain's cross-references with currentmodule directive or currentclass directive. - +* #1444: autosummary does not create the description from attributes docstring. Release 1.2.2 (released Mar 2, 2014) ==================================== diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 0206b30c6..8a23da9ef 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -65,6 +65,7 @@ from docutils import nodes from sphinx import addnodes from sphinx.util.compat import Directive +from sphinx.pycode import ModuleAnalyzer, PycodeError # -- autosummary_toc node ------------------------------------------------------ @@ -192,6 +193,7 @@ class Autosummary(Directive): self.env = env = self.state.document.settings.env self.genopt = {} self.warnings = [] + self.result = ViewList() names = [x.strip().split()[0] for x in self.content if x.strip() and re.search(r'^[~a-zA-Z_]', x.strip()[0])] @@ -249,6 +251,7 @@ class Autosummary(Directive): # NB. using real_name here is important, since Documenters # handle module prefixes slightly differently + self.result = ViewList() # initialize for each documenter documenter = get_documenter(obj, parent)(self, real_name) if not documenter.parse_name(): self.warn('failed to parse name %s' % real_name) @@ -259,6 +262,17 @@ class Autosummary(Directive): items.append((display_name, '', '', real_name)) continue + # try to also get a source code analyzer for attribute docs + try: + documenter.analyzer = ModuleAnalyzer.for_module(documenter.get_real_modname()) + # parse right now, to get PycodeErrors on parsing (results will + # be cached anyway) + documenter.analyzer.find_attr_docs() + except PycodeError, err: + documenter.env.app.debug('[autodoc] module analyzer failed: %s', err) + # no source file -- e.g. for builtin and C modules + documenter.analyzer = None + # -- Grab the signature sig = documenter.format_signature() @@ -271,7 +285,8 @@ class Autosummary(Directive): # -- Grab the summary - doc = list(documenter.process_doc(documenter.get_doc())) + documenter.add_content(None) + doc = list(documenter.process_doc([self.result.data])) while doc and not doc[0].strip(): doc.pop(0) diff --git a/tests/roots/test-autosummary/dummy_module.py b/tests/roots/test-autosummary/dummy_module.py index fd5449613..a150188d5 100644 --- a/tests/roots/test-autosummary/dummy_module.py +++ b/tests/roots/test-autosummary/dummy_module.py @@ -1,3 +1,11 @@ +""" +.. autosummary:: + + module_attr + C.class_attr + C.prop_attr1 + C.prop_attr2 +""" def withSentence(): '''I have a sentence which @@ -19,3 +27,39 @@ def emptyLine(): However, it did't end with a period. ''' pass + + +#: This is a module attribute +#: +#: value is integer. +module_attr = 1 + + +class C: + ''' + My C class + + with class_attr attribute + ''' + + #: This is a class attribute + #: + #: value is integer. + class_attr = 42 + + def _prop_attr_get(self): + """ + This is a function docstring + + return value is string. + """ + return 'spam egg' + + prop_attr1 = property(_prop_attr_get) + + prop_attr2 = property(_prop_attr_get) + """ + This is a attribute docstring + + value is string. + """ diff --git a/tests/test_autosummary.py b/tests/test_autosummary.py index fc506cd95..9ae96a079 100644 --- a/tests/test_autosummary.py +++ b/tests/test_autosummary.py @@ -96,7 +96,35 @@ def test_get_items_summary(): 'withSentence': 'I have a sentence which spans multiple lines.', 'noSentence': "this doesn't start with a", 'emptyLine': "This is the real summary", + 'module_attr': 'This is a module attribute', + 'C.class_attr': 'This is a class attribute', + 'C.prop_attr1': 'This is a function docstring', + 'C.prop_attr2': 'This is a attribute docstring', } for key, expected in expected_values.iteritems(): assert autosummary_items[key][2] == expected, 'Summary for %s was %r -'\ ' expected %r' % (key, autosummary_items[key], expected) + + +@with_app(confoverrides={'extensions': ['sphinx.ext.autosummary'], + 'autosummary_generate': True, + 'source_suffix': '.rst'}, + buildername='html', srcdir=(test_roots / 'test-autosummary')) +def test_process_doc_event(app): + app.builddir.rmtree(True) + + # Now, modify the python path... + srcdir = test_roots / 'test-autosummary' + sys.path.insert(0, srcdir) + try: + def handler(app, what, name, obj, options, lines): + assert isinstance(lines, list) + app.connect('autodoc-process-docstring', handler) + app.builder.build_all() + finally: + if srcdir in sys.path: + sys.path.remove(srcdir) + # remove the auto-generated dummy_module.rst + dummy_rst = srcdir / 'dummy_module.rst' + if dummy_rst.isfile(): + dummy_rst.unlink()