diff --git a/tests/roots/test-ext-autodoc/target/__init__.py b/tests/roots/test-ext-autodoc/target/__init__.py index 771d45c4c..f6970a36c 100644 --- a/tests/roots/test-ext-autodoc/target/__init__.py +++ b/tests/roots/test-ext-autodoc/target/__init__.py @@ -34,26 +34,7 @@ def _funky_classmethod(name, b, c, d, docstring=None): return classmethod(function) -class Base(object): - def inheritedmeth(self): - """Inherited function.""" - - @classmethod - def inheritedclassmeth(cls): - """Inherited class method.""" - - @staticmethod - def inheritedstaticmeth(cls): - """Inherited static method.""" - - -class Derived(Base): - def inheritedmeth(self): - # no docstring here - pass - - -class Class(Base): +class Class(object): """Class to document.""" def meth(self): diff --git a/tests/roots/test-ext-autodoc/target/autoclass_content.py b/tests/roots/test-ext-autodoc/target/autoclass_content.py new file mode 100644 index 000000000..8924ab09b --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/autoclass_content.py @@ -0,0 +1,35 @@ +class A: + """A class having no __init__, no __new__""" + + +class B: + """A class having __init__(no docstring), no __new__""" + def __init__(self): + pass + + +class C: + """A class having __init__, no __new__""" + def __init__(self): + """__init__ docstring""" + + +class D: + """A class having no __init__, __new__(no docstring)""" + def __new__(cls): + pass + + +class E: + """A class having no __init__, __new__""" + def __new__(cls): + """__new__ docstring""" + + +class F: + """A class having both __init__ and __new__""" + def __init__(self): + """__init__ docstring""" + + def __new__(cls): + """__new__ docstring""" diff --git a/tests/roots/test-ext-autodoc/target/docstring_signature.py b/tests/roots/test-ext-autodoc/target/docstring_signature.py new file mode 100644 index 000000000..2e5499770 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/docstring_signature.py @@ -0,0 +1,19 @@ +class A: + """A(foo, bar)""" + + +class B: + """B(foo, bar)""" + def __init__(self): + """B(foo, bar, baz)""" + + +class C: + """C(foo, bar)""" + def __new__(cls): + """C(foo, bar, baz)""" + + +class D: + def __init__(self): + """D(foo, bar, baz)""" diff --git a/tests/roots/test-ext-autodoc/target/inheritance.py b/tests/roots/test-ext-autodoc/target/inheritance.py new file mode 100644 index 000000000..3a5fc0711 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/inheritance.py @@ -0,0 +1,19 @@ +class Base(object): + def inheritedmeth(self): + """Inherited function.""" + + @classmethod + def inheritedclassmeth(cls): + """Inherited class method.""" + + @staticmethod + def inheritedstaticmeth(cls): + """Inherited static method.""" + + +class Derived(Base): + def inheritedmeth(self): + # no docstring here + pass + + diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 877c8a204..98f8f1a99 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -325,127 +325,6 @@ def test_get_doc(): """Döcstring""" assert getdocl('function', f) == ['Döcstring'] - # class docstring: depends on config value which one is taken - class C: - """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' - assert getdocl('class', C) == ['Init docstring'] - directive.env.config.autoclass_content = 'both' - assert getdocl('class', C) == ['Class docstring', '', 'Init docstring'] - - class D: - """Class docstring""" - def __init__(self): - """Init docstring - - Other - lines - """ - - # Indentation is normalized for 'both' - assert getdocl('class', D) == ['Class docstring', '', 'Init docstring', - '', 'Other', ' lines'] - - # __init__ have signature at first line of docstring - class E: - """Class docstring""" - def __init__(self, *args, **kw): - """ - __init__(a1, a2, kw1=True, kw2=False) - - Init docstring - """ - - # signature line in the docstring will be kept when - # autodoc_docstring_signature == False - directive.env.config.autodoc_docstring_signature = False - directive.env.config.autoclass_content = 'class' - assert getdocl('class', E) == ['Class docstring'] - directive.env.config.autoclass_content = 'init' - assert getdocl('class', E) == ['__init__(a1, a2, kw1=True, kw2=False)', - '', 'Init docstring'] - directive.env.config.autoclass_content = 'both' - assert getdocl('class', E) == ['Class docstring', '', - '__init__(a1, a2, kw1=True, kw2=False)', - '', 'Init docstring'] - - # signature line in the docstring will be removed when - # autodoc_docstring_signature == True - directive.env.config.autodoc_docstring_signature = True # default - directive.env.config.autoclass_content = 'class' - assert getdocl('class', E) == ['Class docstring'] - directive.env.config.autoclass_content = 'init' - assert getdocl('class', E) == ['Init docstring'] - directive.env.config.autoclass_content = 'both' - assert getdocl('class', E) == ['Class docstring', '', 'Init docstring'] - - # class does not have __init__ method - class F: - """Class docstring""" - - # docstring in the __init__ method of base class will be discard - for f in (False, True): - directive.env.config.autodoc_docstring_signature = f - directive.env.config.autoclass_content = 'class' - assert getdocl('class', F) == ['Class docstring'] - directive.env.config.autoclass_content = 'init' - assert getdocl('class', F) == ['Class docstring'] - directive.env.config.autoclass_content = 'both' - assert getdocl('class', F) == ['Class docstring'] - - # class has __init__ method with no docstring - class G: - """Class docstring""" - def __init__(self): - pass - - # docstring in the __init__ method of base class will not be used - for f in (False, True): - directive.env.config.autodoc_docstring_signature = f - directive.env.config.autoclass_content = 'class' - assert getdocl('class', G) == ['Class docstring'] - directive.env.config.autoclass_content = 'init' - assert getdocl('class', G) == ['Class docstring'] - 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: # NOQA - """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'] - # verify that method docstrings get extracted in both normal case # and in case of bound method posing as a function class J: # NOQA @@ -454,15 +333,6 @@ def test_get_doc(): assert getdocl('method', J.foo) == ['Method docstring'] assert getdocl('function', J().foo) == ['Method docstring'] - from target import Base, Derived - - # NOTE: inspect.getdoc seems not to work with locally defined classes - directive.env.config.autodoc_inherit_docstrings = False - assert getdocl('method', Base.inheritedmeth) == ['Inherited function.'] - assert getdocl('method', Derived.inheritedmeth) == [] - directive.env.config.autodoc_inherit_docstrings = True - assert getdocl('method', Derived.inheritedmeth) == ['Inherited function.'] - @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_new_documenter(app): @@ -498,6 +368,7 @@ def test_new_documenter(app): @pytest.mark.usefixtures('setup_test') def test_attrgetter_using(): from target import Class + from target.inheritance import Derived def assert_getter_works(objtype, name, obj, attrs=[], **kw): getattr_spy = [] @@ -527,7 +398,7 @@ def test_attrgetter_using(): assert_getter_works('class', 'target.Class', Class, ['meth']) options.inherited_members = True - assert_getter_works('class', 'target.Class', Class, ['meth', 'inheritedmeth']) + assert_getter_works('class', 'target.inheritance.Derived', Derived, ['inheritedmeth']) @pytest.mark.sphinx('html', testroot='ext-autodoc') @@ -630,14 +501,14 @@ def test_autodoc_attributes(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_members(app): # default (no-members) - actual = do_autodoc(app, 'class', 'target.Base') + actual = do_autodoc(app, 'class', 'target.inheritance.Base') assert list(filter(lambda l: '::' in l, actual)) == [ '.. py:class:: Base', ] # default ALL-members options = {"members": None} - actual = do_autodoc(app, 'class', 'target.Base', options) + actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) assert list(filter(lambda l: '::' in l, actual)) == [ '.. py:class:: Base', ' .. py:method:: Base.inheritedclassmeth()', @@ -647,7 +518,7 @@ def test_autodoc_members(app): # default specific-members options = {"members": "inheritedmeth,inheritedstaticmeth"} - actual = do_autodoc(app, 'class', 'target.Base', options) + actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) assert list(filter(lambda l: '::' in l, actual)) == [ '.. py:class:: Base', ' .. py:method:: Base.inheritedmeth()', @@ -659,7 +530,7 @@ def test_autodoc_members(app): def test_autodoc_exclude_members(app): options = {"members": None, "exclude-members": "inheritedmeth,inheritedstaticmeth"} - actual = do_autodoc(app, 'class', 'target.Base', options) + actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) assert list(filter(lambda l: '::' in l, actual)) == [ '.. py:class:: Base', ' .. py:method:: Base.inheritedclassmeth()' @@ -668,7 +539,7 @@ def test_autodoc_exclude_members(app): # members vs exclude-members options = {"members": "inheritedmeth", "exclude-members": "inheritedmeth"} - actual = do_autodoc(app, 'class', 'target.Base', options) + actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) assert list(filter(lambda l: '::' in l, actual)) == [ '.. py:class:: Base', ] @@ -702,15 +573,11 @@ def test_autodoc_undoc_members(app): def test_autodoc_inherited_members(app): options = {"members": None, "inherited-members": None} - actual = do_autodoc(app, 'class', 'target.Class', options) + actual = do_autodoc(app, 'class', 'target.inheritance.Derived', options) assert list(filter(lambda l: 'method::' in l, actual)) == [ - ' .. py:method:: Class.excludemeth()', - ' .. py:method:: Class.inheritedclassmeth()', - ' .. py:method:: Class.inheritedmeth()', - ' .. py:method:: Class.inheritedstaticmeth(cls)', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:method:: Class.skipmeth()' + ' .. py:method:: Derived.inheritedclassmeth()', + ' .. py:method:: Derived.inheritedmeth()', + ' .. py:method:: Derived.inheritedstaticmeth(cls)', ] @@ -755,10 +622,12 @@ def test_autodoc_special_members(app): actual = do_autodoc(app, 'class', 'target.Class', options) assert list(filter(lambda l: '::' in l, actual)) == [ '.. py:class:: Class(arg)', + ' .. py:attribute:: Class.__dict__', ' .. py:method:: Class.__init__(arg)', ' .. py:attribute:: Class.__module__', ' .. py:method:: Class.__special1__()', ' .. py:method:: Class.__special2__()', + ' .. py:attribute:: Class.__weakref__', ' .. py:attribute:: Class.attr', ' .. py:attribute:: Class.docattr', ' .. py:method:: Class.excludemeth()', @@ -812,12 +681,12 @@ def test_autodoc_noindex(app): # TODO: :noindex: should be propagated to children of target item. - actual = do_autodoc(app, 'class', 'target.Base', options) + actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) assert list(actual) == [ '', '.. py:class:: Base', ' :noindex:', - ' :module: target', + ' :module: target.inheritance', '' ] @@ -885,11 +754,11 @@ def test_autodoc_inner_class(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_classmethod(app): - actual = do_autodoc(app, 'method', 'target.Base.inheritedclassmeth') + actual = do_autodoc(app, 'method', 'target.inheritance.Base.inheritedclassmeth') assert list(actual) == [ '', '.. py:method:: Base.inheritedclassmeth()', - ' :module: target', + ' :module: target.inheritance', ' :classmethod:', '', ' Inherited class method.', @@ -899,11 +768,11 @@ def test_autodoc_classmethod(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_staticmethod(app): - actual = do_autodoc(app, 'method', 'target.Base.inheritedstaticmeth') + actual = do_autodoc(app, 'method', 'target.inheritance.Base.inheritedstaticmeth') assert list(actual) == [ '', '.. py:method:: Base.inheritedstaticmeth(cls)', - ' :module: target', + ' :module: target.inheritance', ' :staticmethod:', '', ' Inherited static method.', diff --git a/tests/test_ext_autodoc_configs.py b/tests/test_ext_autodoc_configs.py index cc8f9dbc1..bbf3debaa 100644 --- a/tests/test_ext_autodoc_configs.py +++ b/tests/test_ext_autodoc_configs.py @@ -18,6 +18,180 @@ from test_autodoc import do_autodoc IS_PYPY = platform.python_implementation() == 'PyPy' +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoclass_content_class(app): + app.config.autoclass_content = 'class' + options = {"members": None} + actual = do_autodoc(app, 'module', 'target.autoclass_content', options) + assert list(actual) == [ + '', + '.. py:module:: target.autoclass_content', + '', + '', + '.. py:class:: A', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, no __new__', + ' ', + '', + '.. py:class:: B()', + ' :module: target.autoclass_content', + '', + ' A class having __init__(no docstring), no __new__', + ' ', + '', + '.. py:class:: C()', + ' :module: target.autoclass_content', + '', + ' A class having __init__, no __new__', + ' ', + '', + '.. py:class:: D', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, __new__(no docstring)', + ' ', + '', + '.. py:class:: E', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, __new__', + ' ', + '', + '.. py:class:: F()', + ' :module: target.autoclass_content', + '', + ' A class having both __init__ and __new__', + ' ' + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoclass_content_init(app): + app.config.autoclass_content = 'init' + options = {"members": None} + actual = do_autodoc(app, 'module', 'target.autoclass_content', options) + assert list(actual) == [ + '', + '.. py:module:: target.autoclass_content', + '', + '', + '.. py:class:: A', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, no __new__', + ' ', + '', + '.. py:class:: B()', + ' :module: target.autoclass_content', + '', + ' A class having __init__(no docstring), no __new__', + ' ', + '', + '.. py:class:: C()', + ' :module: target.autoclass_content', + '', + ' __init__ docstring', + ' ', + '', + '.. py:class:: D', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, __new__(no docstring)', + ' ', + '', + '.. py:class:: E', + ' :module: target.autoclass_content', + '', + ' __new__ docstring', + ' ', + '', + '.. py:class:: F()', + ' :module: target.autoclass_content', + '', + ' __init__ docstring', + ' ' + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoclass_content_both(app): + app.config.autoclass_content = 'both' + options = {"members": None} + actual = do_autodoc(app, 'module', 'target.autoclass_content', options) + assert list(actual) == [ + '', + '.. py:module:: target.autoclass_content', + '', + '', + '.. py:class:: A', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, no __new__', + ' ', + '', + '.. py:class:: B()', + ' :module: target.autoclass_content', + '', + ' A class having __init__(no docstring), no __new__', + ' ', + '', + '.. py:class:: C()', + ' :module: target.autoclass_content', + '', + ' A class having __init__, no __new__', + ' ', + ' __init__ docstring', + ' ', + '', + '.. py:class:: D', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, __new__(no docstring)', + ' ', + '', + '.. py:class:: E', + ' :module: target.autoclass_content', + '', + ' A class having no __init__, __new__', + ' ', + ' __new__ docstring', + ' ', + '', + '.. py:class:: F()', + ' :module: target.autoclass_content', + '', + ' A class having both __init__ and __new__', + ' ', + ' __init__ docstring', + ' ' + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodoc_inherit_docstrings(app): + assert app.config.autodoc_inherit_docstrings is True # default + actual = do_autodoc(app, 'method', 'target.inheritance.Derived.inheritedmeth') + assert list(actual) == [ + '', + '.. py:method:: Derived.inheritedmeth()', + ' :module: target.inheritance', + '', + ' Inherited function.', + ' ' + ] + + # disable autodoc_inherit_docstrings + app.config.autodoc_inherit_docstrings = False + actual = do_autodoc(app, 'method', 'target.inheritance.Derived.inheritedmeth') + assert list(actual) == [ + '', + '.. py:method:: Derived.inheritedmeth()', + ' :module: target.inheritance', + '' + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_docstring_signature(app): options = {"members": None} @@ -107,6 +281,97 @@ def test_autodoc_docstring_signature(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoclass_content_and_docstring_signature_class(app): + app.config.autoclass_content = 'class' + options = {"members": None, + "undoc-members": None} + actual = do_autodoc(app, 'module', 'target.docstring_signature', options) + assert list(actual) == [ + '', + '.. py:module:: target.docstring_signature', + '', + '', + '.. py:class:: A(foo, bar)', + ' :module: target.docstring_signature', + '', + '', + '.. py:class:: B(foo, bar)', + ' :module: target.docstring_signature', + '', + '', + '.. py:class:: C(foo, bar)', + ' :module: target.docstring_signature', + '', + '', + '.. py:class:: D()', + ' :module: target.docstring_signature', + '' + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoclass_content_and_docstring_signature_init(app): + app.config.autoclass_content = 'init' + options = {"members": None, + "undoc-members": None} + actual = do_autodoc(app, 'module', 'target.docstring_signature', options) + assert list(actual) == [ + '', + '.. py:module:: target.docstring_signature', + '', + '', + '.. py:class:: A(foo, bar)', + ' :module: target.docstring_signature', + '', + '', + '.. py:class:: B(foo, bar, baz)', + ' :module: target.docstring_signature', + '', + '', + '.. py:class:: C(foo, bar, baz)', + ' :module: target.docstring_signature', + '', + '', + '.. py:class:: D(foo, bar, baz)', + ' :module: target.docstring_signature', + '' + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoclass_content_and_docstring_signature_both(app): + app.config.autoclass_content = 'both' + options = {"members": None, + "undoc-members": None} + actual = do_autodoc(app, 'module', 'target.docstring_signature', options) + assert list(actual) == [ + '', + '.. py:module:: target.docstring_signature', + '', + '', + '.. py:class:: A(foo, bar)', + ' :module: target.docstring_signature', + '', + '', + '.. py:class:: B(foo, bar)', + ' :module: target.docstring_signature', + '', + ' B(foo, bar, baz)', + ' ', + '', + '.. py:class:: C(foo, bar)', + ' :module: target.docstring_signature', + '', + ' C(foo, bar, baz)', + ' ', + '', + '.. py:class:: D(foo, bar, baz)', + ' :module: target.docstring_signature', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_mocked_module_imports(app, warning): # no autodoc_mock_imports