diff --git a/CHANGES b/CHANGES index a71f25aaa5c..2cec105d868 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Features added * #8588: autodoc: :confval:`autodoc_type_aliases` now supports dotted name. It allows you to define an alias for a class with module name like ``foo.bar.BazClass`` +* #9175: autodoc: Special member is not documented in the module * #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/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index ff6475c9442..fa0b6af74c5 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -709,6 +709,8 @@ def is_filtered_inherited_member(name: str, obj: Any) -> bool: # if isattr is True, the member is documented as an attribute if member is INSTANCEATTR: isattr = True + elif (namespace, membername) in attr_docs: + isattr = True else: isattr = False @@ -769,7 +771,6 @@ def is_filtered_inherited_member(name: str, obj: Any) -> bool: else: # keep documented attributes keep = True - isattr = True elif want_all and isprivate: if has_doc or self.options.undoc_members: if self.options.private_members is None: diff --git a/tests/roots/test-ext-autodoc/target/module.py b/tests/roots/test-ext-autodoc/target/module.py new file mode 100644 index 00000000000..fe3b490a92d --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/module.py @@ -0,0 +1,14 @@ +undocumented = 1 + +#: docstring +documented = 1 + +undoc_annotated: int + +#: docstring +annotated: int + +__special__ = 1 + +#: docstring +__documented_special__ = 1 diff --git a/tests/test_ext_autodoc_automodule.py b/tests/test_ext_autodoc_automodule.py index 3332704bbe6..59296a981a3 100644 --- a/tests/test_ext_autodoc_automodule.py +++ b/tests/test_ext_autodoc_automodule.py @@ -29,6 +29,95 @@ def test_empty_all(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_automodule(app): + options = {'members': None} + actual = do_autodoc(app, 'module', 'target.module', options) + assert list(actual) == [ + '', + '.. py:module:: target.module', + '', + '', + '.. py:data:: annotated', + ' :module: target.module', + ' :type: int', + '', + ' docstring', + '', + '', + '.. py:data:: documented', + ' :module: target.module', + ' :value: 1', + '', + ' docstring', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_automodule_undoc_members(app): + options = {'members': None, + 'undoc-members': None} + actual = do_autodoc(app, 'module', 'target.module', options) + assert list(actual) == [ + '', + '.. py:module:: target.module', + '', + '', + '.. py:data:: annotated', + ' :module: target.module', + ' :type: int', + '', + ' docstring', + '', + '', + '.. py:data:: documented', + ' :module: target.module', + ' :value: 1', + '', + ' docstring', + '', + '', + '.. py:data:: undoc_annotated', + ' :module: target.module', + ' :type: int', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_automodule_special_members(app): + options = {'members': None, + 'special-members': None} + actual = do_autodoc(app, 'module', 'target.module', options) + assert list(actual) == [ + '', + '.. py:module:: target.module', + '', + '', + '.. py:data:: __documented_special__', + ' :module: target.module', + ' :value: 1', + '', + ' docstring', + '', + '', + '.. py:data:: annotated', + ' :module: target.module', + ' :type: int', + '', + ' docstring', + '', + '', + '.. py:data:: documented', + ' :module: target.module', + ' :value: 1', + '', + ' docstring', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc', confoverrides={'autodoc_mock_imports': ['missing_module', 'missing_package1',