From 0311f33347d7c49613f3249ecaa6028f1eddeef8 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Fri, 5 Feb 2016 19:09:43 +0100 Subject: [PATCH] Feature: enhance autoclass:: to use the docstring of __new__ The method new is an alternative to __init__, but autoclass does not respect __new__. This commit enhances the directive autoclass:: to try __new__ method's docstring, if __init__ method's docstring is missing or empty. The commit also adds tests and updates the documentation. --- doc/ext/autodoc.rst | 6 ++++++ sphinx/ext/autodoc.py | 9 +++++++++ tests/test_autodoc.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst index 844c63684..0ceb79096 100644 --- a/doc/ext/autodoc.rst +++ b/doc/ext/autodoc.rst @@ -314,6 +314,12 @@ There are also new config values that you can set: .. versionadded:: 0.3 + If the class has no ``__init__`` method or if the ``__init__`` method's + docstring is empty, but the class has a ``__new__`` method's docstring, + it is used instead. + + .. versionadded:: 1.4 + .. confval:: autodoc_member_order This value selects if automatically documented members are sorted diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index f906d9666..115e4f3fc 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -1163,6 +1163,15 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): (initdocstring == object.__init__.__doc__ or # for pypy initdocstring.strip() == object.__init__.__doc__)): # for !pypy initdocstring = None + if not initdocstring: + # try __new__ + initdocstring = self.get_attr( + self.get_attr(self.object, '__new__', None), '__doc__') + # for new-style classes, no __new__ means default __new__ + if (initdocstring is not None and + (initdocstring == object.__new__.__doc__ or # for pypy + initdocstring.strip() == object.__new__.__doc__)): # for !pypy + initdocstring = None if initdocstring: if content == 'init': docstrings = [initdocstring] diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 5c2bc7ff5..068cf1da0 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -297,6 +297,9 @@ def test_get_doc(): """Class docstring""" def __init__(self): """Init docstring""" + + def __new__(cls): + """New docstring""" directive.env.config.autoclass_content = 'class' assert getdocl('class', C) == ['Class docstring'] directive.env.config.autoclass_content = 'init' @@ -380,6 +383,36 @@ def test_get_doc(): directive.env.config.autoclass_content = 'both' assert getdocl('class', G) == ['Class docstring'] + # class has __new__ method with docstring + # class docstring: depends on config value which one is taken + class H: + """Class docstring""" + def __init__(self): + pass + + def __new__(cls): + """New docstring""" + directive.env.config.autoclass_content = 'class' + assert getdocl('class', H) == ['Class docstring'] + directive.env.config.autoclass_content = 'init' + assert getdocl('class', H) == ['New docstring'] + directive.env.config.autoclass_content = 'both' + assert getdocl('class', H) == ['Class docstring', '', 'New docstring'] + + # class has __init__ method without docstring and + # __new__ method with docstring + # class docstring: depends on config value which one is taken + class I: + """Class docstring""" + def __new__(cls): + """New docstring""" + directive.env.config.autoclass_content = 'class' + assert getdocl('class', I) == ['Class docstring'] + directive.env.config.autoclass_content = 'init' + assert getdocl('class', I) == ['New docstring'] + directive.env.config.autoclass_content = 'both' + assert getdocl('class', I) == ['Class docstring', '', 'New docstring'] + @with_setup(setup_test) def test_docstring_processing():