Fix #2401: autodoc: `:members: causes :special-members:` not to be shown

This commit is contained in:
Takeshi KOMIYA 2018-09-02 22:30:51 +09:00
parent c6e0d92d10
commit 06aa1a7864
5 changed files with 55 additions and 35 deletions

View File

@ -30,6 +30,7 @@ Bugs fixed
* #5348: download reference to remote file is not displayed
* #5282: html theme: ``pygments_style`` of theme was overrided by ``conf.py``
by default
* #2401: autodoc: ``:members:`` causes ``:special-members:`` not to be shown
Testing
--------

View File

@ -110,6 +110,20 @@ def bool_option(arg):
return True
def merge_special_members_option(options):
# type: (Dict) -> None
"""Merge :special-members: option to :members: option."""
if 'special-members' in options and options['special-members'] is not ALL:
if options.get('members') is ALL:
pass
elif options.get('members'):
for member in options['special-members']:
if member not in options['members']:
options['members'].append(member)
else:
options['members'] = options['special-members']
class AutodocReporter(object):
"""
A reporter replacement that assigns the correct source name
@ -823,6 +837,11 @@ class ModuleDocumenter(Documenter):
'imported-members': bool_option, 'ignore-module-all': bool_option
} # type: Dict[unicode, Callable]
def __init__(self, *args):
# type: (Any) -> None
super(ModuleDocumenter, self).__init__(*args)
merge_special_members_option(self.options)
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
# type: (Any, unicode, bool, Any) -> bool
@ -1075,6 +1094,11 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
'private-members': bool_option, 'special-members': members_option,
} # type: Dict[unicode, Callable]
def __init__(self, *args):
# type: (Any) -> None
super(ClassDocumenter, self).__init__(*args)
merge_special_members_option(self.options)
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
# type: (Any, unicode, bool, Any) -> bool

View File

@ -43,11 +43,12 @@ from sphinx.util.rst import escape as rst_escape
if False:
# For type annotation
from typing import Any, Callable, Dict, Tuple, List # NOQA
from typing import Any, Callable, Dict, List, Tuple, Type # NOQA
from jinja2 import BaseLoader # NOQA
from sphinx import addnodes # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc import Documenter # NOQA
class DummyApplication(object):
@ -69,7 +70,7 @@ def setup_documenters(app):
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
FunctionDocumenter, MethodDocumenter, AttributeDocumenter,
InstanceAttributeDocumenter
]
] # type: List[Type[Documenter]]
for documenter in documenters:
app.registry.add_documenter(documenter.objtype, documenter)

View File

@ -18,7 +18,7 @@ import six
from docutils.statemachine import ViewList
from six import StringIO
from sphinx.ext.autodoc import add_documenter, FunctionDocumenter, ALL # NOQA
from sphinx.ext.autodoc import add_documenter, FunctionDocumenter, ALL, Options # NOQA
from sphinx.testing.util import SphinxTestApp, Struct
from sphinx.util import logging
@ -49,7 +49,7 @@ def setup_test():
global options, directive
global processed_docstrings, processed_signatures
options = Struct(
options = Options(
inherited_members = False,
undoc_members = False,
private_members = False,

View File

@ -21,7 +21,7 @@ from six import PY3
from sphinx.ext.autodoc import (
AutoDirective, ModuleLevelDocumenter, cut_lines, between, ALL,
merge_autodoc_default_flags
merge_autodoc_default_flags, Options
)
from sphinx.ext.autodoc.directive import DocumenterBridge, process_documenter_options
from sphinx.testing.util import SphinxTestApp, Struct # NOQA
@ -79,7 +79,7 @@ def setup_test():
global options, directive
global processed_docstrings, processed_signatures
options = Struct(
options = Options(
inherited_members = False,
undoc_members = False,
private_members = False,
@ -757,6 +757,29 @@ def test_autodoc_imported_members(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_special_members(app):
# specific special methods
options = {"undoc-members": None,
"special-members": "__init__,__special1__"}
actual = do_autodoc(app, 'class', 'target.Class', options)
assert list(filter(lambda l: '::' in l, actual)) == [
'.. py:class:: Class(arg)',
' .. py:method:: Class.__init__(arg)',
' .. py:method:: Class.__special1__()',
]
# combination with specific members
options = {"members": "attr,docattr",
"undoc-members": None,
"special-members": "__init__,__special1__"}
actual = do_autodoc(app, 'class', 'target.Class', options)
assert list(filter(lambda l: '::' in l, actual)) == [
'.. py:class:: Class(arg)',
' .. py:method:: Class.__init__(arg)',
' .. py:method:: Class.__special1__()',
' .. py:attribute:: Class.attr',
' .. py:attribute:: Class.docattr',
]
# all special methods
options = {"members": None,
"undoc-members": None,
@ -786,33 +809,6 @@ def test_autodoc_special_members(app):
' .. py:method:: Class.undocmeth()'
]
# specific special methods
options = {"members": None,
"undoc-members": None,
"special-members": "__init__,__special1__"}
actual = do_autodoc(app, 'class', 'target.Class', options)
assert list(filter(lambda l: '::' in l, actual)) == [
'.. py:class:: Class(arg)',
' .. py:method:: Class.__init__(arg)',
' .. py:method:: Class.__special1__()',
' .. py:attribute:: Class.attr',
' .. py:attribute:: Class.descr',
' .. py:attribute:: Class.docattr',
' .. py:method:: Class.excludemeth()',
' .. py:attribute:: Class.inst_attr_comment',
' .. py:attribute:: Class.inst_attr_inline',
' .. py:attribute:: Class.inst_attr_string',
' .. py:attribute:: Class.mdocattr',
' .. py:method:: Class.meth()',
' .. py:classmethod:: Class.moore(a, e, f) -> happiness',
' .. py:attribute:: Class.prop',
ROGER_METHOD,
' .. py:attribute:: Class.skipattr',
' .. py:method:: Class.skipmeth()',
' .. py:attribute:: Class.udocattr',
' .. py:method:: Class.undocmeth()'
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_ignore_module_all(app):
@ -1551,9 +1547,7 @@ def test_autodoc_default_options_with_values(app):
assert ' .. py:attribute:: EnumCls.val4' not in actual
# with :special-members:
# Note that :members: must be *on* for :special-members: to work.
app.config.autodoc_default_options = {
'members': None,
'special-members': '__init__,__iter__',
}
actual = do_autodoc(app, 'class', 'target.CustomIter')