Merge pull request #9171 from tk0miya/4257_autodoc_class_signature

Close #4257: autodoc: Add autodoc_class_signature
This commit is contained in:
Takeshi KOMIYA 2021-05-16 02:03:54 +09:00 committed by GitHub
commit 99f4672575
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 116 additions and 0 deletions

View File

@ -28,6 +28,8 @@ Features added
* #9195: autodoc: The arguments of ``typing.Literal`` are wrongly rendered
* #9185: autodoc: :confval:`autodoc_typehints` allows ``'both'`` setting to
allow typehints to be included both in the signature and description
* #4257: autodoc: Add :confval:`autodoc_class_signature` to separate the class
entry and the definition of ``__init__()`` method
* #3257: autosummary: Support instance attributes for classes
* #9129: html search: Show search summaries when html_copy_source = False
* #9120: html theme: Eliminate prompt characters of code-block from copyable

View File

@ -463,6 +463,20 @@ There are also config values that you can set:
.. versionadded:: 1.4
.. confval:: autodoc_class_signature
This value selects how the signautre will be displayed for the class defined
by :rst:dir:`autoclass` directive. The possible values are:
``"mixed"``
Display the signature with the class name.
``"separated"``
Display the signature as a method.
The default is ``"mixed"``.
.. versionadded:: 4.1
.. confval:: autodoc_member_order
This value selects if automatically documented members are sorted

View File

@ -70,6 +70,9 @@ class _All:
def __contains__(self, item: Any) -> bool:
return True
def append(self, item: Any) -> None:
pass # nothing
class _Empty:
"""A special value for :exclude-members: that never matches to any member."""
@ -1440,6 +1443,15 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
def __init__(self, *args: Any) -> None:
super().__init__(*args)
if self.config.autodoc_class_signature == 'separated':
# show __init__() method
if self.options.special_members is None:
self.options['special-members'] = {'__new__', '__init__'}
else:
self.options.special_members.append('__new__')
self.options.special_members.append('__init__')
merge_members_option(self.options)
@classmethod
@ -1556,6 +1568,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
def format_signature(self, **kwargs: Any) -> str:
if self.doc_as_attr:
return ''
if self.config.autodoc_class_signature == 'separated':
# do not show signatures
return ''
sig = super().format_signature()
sigs = []
@ -2193,6 +2208,38 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
else:
return None
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
if self.objpath[-1] == '__init__':
docstring = getdoc(self.object, self.get_attr,
self.config.autodoc_inherit_docstrings,
self.parent, self.object_name)
if (docstring is not None and
(docstring == object.__init__.__doc__ or # for pypy
docstring.strip() == object.__init__.__doc__)): # for !pypy
docstring = None
if docstring:
tab_width = self.directive.state.document.settings.tab_width
return [prepare_docstring(docstring, tabsize=tab_width)]
else:
return []
elif self.objpath[-1] == '__new__':
__new__ = self.get_attr(self.object, '__new__', None)
if __new__:
docstring = getdoc(__new__, self.get_attr,
self.config.autodoc_inherit_docstrings,
self.parent, self.object_name)
if (docstring is not None and
(docstring == object.__new__.__doc__ or # for pypy
docstring.strip() == object.__new__.__doc__)): # for !pypy
docstring = None
if docstring:
tab_width = self.directive.state.document.settings.tab_width
return [prepare_docstring(docstring, tabsize=tab_width)]
else:
return []
else:
return super().get_doc()
class NonDataDescriptorMixin(DataDocumenterMixinBase):
"""
@ -2662,6 +2709,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init'))
app.add_config_value('autodoc_member_order', 'alphabetical', True,
ENUM('alphabetic', 'alphabetical', 'bysource', 'groupwise'))
app.add_config_value('autodoc_class_signature', 'mixed', True, ENUM('mixed', 'separated'))
app.add_config_value('autodoc_default_options', {}, True)
app.add_config_value('autodoc_docstring_signature', True, True)
app.add_config_value('autodoc_mock_imports', [], True)

View File

@ -174,6 +174,7 @@ class FakeDirective(DocumenterBridge):
document = Struct(settings=settings)
env = BuildEnvironment()
env.config = Config()
env.config.add('autodoc_class_signature', 'mixed', True, None)
state = Struct(document=document)
super().__init__(env, None, Options(), 0, state)

View File

@ -140,6 +140,57 @@ def test_autoclass_content_init(app):
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_class_signature_mixed(app):
app.config.autodoc_class_signature = 'mixed'
options = {"members": None,
"undoc-members": None}
actual = do_autodoc(app, 'class', 'target.classes.Bar', options)
assert list(actual) == [
'',
'.. py:class:: Bar(x, y)',
' :module: target.classes',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_class_signature_separated_init(app):
app.config.autodoc_class_signature = 'separated'
options = {"members": None,
"undoc-members": None}
actual = do_autodoc(app, 'class', 'target.classes.Bar', options)
assert list(actual) == [
'',
'.. py:class:: Bar',
' :module: target.classes',
'',
'',
' .. py:method:: Bar.__init__(x, y)',
' :module: target.classes',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_class_signature_separated_new(app):
app.config.autodoc_class_signature = 'separated'
options = {"members": None,
"undoc-members": None}
actual = do_autodoc(app, 'class', 'target.classes.Baz', options)
assert list(actual) == [
'',
'.. py:class:: Baz',
' :module: target.classes',
'',
'',
' .. py:method:: Baz.__new__(cls, x, y)',
' :module: target.classes',
' :staticmethod:',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoclass_content_both(app):
app.config.autoclass_content = 'both'