summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2020-04-14 01:57:43 +0900
committerTakeshi KOMIYA <i.tkomiya@gmail.com>2021-05-16 01:53:48 +0900
commit51ae283a38ed297df3fd5e0554dcc9acaa103e8c (patch)
tree39271b411933709419a9fe976a6a0cfa51e99c0f
parent1513d5077439b6f1e69108233d1a08059f420970 (diff)
downloadsphinx-git-51ae283a38ed297df3fd5e0554dcc9acaa103e8c.tar.gz
Close #4257: autodoc: Add autodoc_class_signature
Add `autodoc_class_signature` to separate the class entry and the definition of `__init__()` method.
-rw-r--r--CHANGES2
-rw-r--r--doc/usage/extensions/autodoc.rst14
-rw-r--r--sphinx/ext/autodoc/__init__.py48
-rw-r--r--sphinx/ext/autosummary/__init__.py1
-rw-r--r--tests/test_ext_autodoc_configs.py51
5 files changed, 116 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index 3ef0bb53e..da8580fe6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst
index e547e698b..2c9e19a8e 100644
--- a/doc/usage/extensions/autodoc.rst
+++ b/doc/usage/extensions/autodoc.rst
@@ -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
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py
index c64496139..1f4c98284 100644
--- a/sphinx/ext/autodoc/__init__.py
+++ b/sphinx/ext/autodoc/__init__.py
@@ -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)
diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py
index be9f0cc65..0bf921f0b 100644
--- a/sphinx/ext/autosummary/__init__.py
+++ b/sphinx/ext/autosummary/__init__.py
@@ -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)
diff --git a/tests/test_ext_autodoc_configs.py b/tests/test_ext_autodoc_configs.py
index b9bed1635..e0f08ea77 100644
--- a/tests/test_ext_autodoc_configs.py
+++ b/tests/test_ext_autodoc_configs.py
@@ -141,6 +141,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'
options = {"members": None}