mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #9831 from Yoshanuikabundi/autosummary___all__
Allow autosummary to respect __all__
This commit is contained in:
commit
15d834e4d8
4
CHANGES
4
CHANGES
@ -15,6 +15,10 @@ Features added
|
|||||||
|
|
||||||
* #9815: html theme: Wrap sidebar components in div to allow customizing their
|
* #9815: html theme: Wrap sidebar components in div to allow customizing their
|
||||||
layout via CSS
|
layout via CSS
|
||||||
|
* #9831: Autosummary now documents only the members specified in a module's
|
||||||
|
``__all__`` attribute if :confval:`autosummary_ignore_module_all` is set to
|
||||||
|
``False``. The default behaviour is unchanged. Autogen also now supports
|
||||||
|
this behavior with the ``--respect-module-all`` switch.
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
@ -39,6 +39,10 @@ Options
|
|||||||
|
|
||||||
Document imported members.
|
Document imported members.
|
||||||
|
|
||||||
|
.. option:: -a, --respect-module-all
|
||||||
|
|
||||||
|
Document exactly the members in a module's ``__all__`` attribute.
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -201,6 +201,25 @@ also use these config values:
|
|||||||
|
|
||||||
.. versionadded:: 2.1
|
.. versionadded:: 2.1
|
||||||
|
|
||||||
|
.. versionchanged:: 4.4
|
||||||
|
|
||||||
|
If ``autosummary_ignore_module_all`` is ``False``, this configuration
|
||||||
|
value is ignored for members listed in ``__all__``.
|
||||||
|
|
||||||
|
.. confval:: autosummary_ignore_module_all
|
||||||
|
|
||||||
|
If ``False`` and a module has the ``__all__`` attribute set, autosummary
|
||||||
|
documents every member listed in ``__all__`` and no others. Default is
|
||||||
|
``True``
|
||||||
|
|
||||||
|
Note that if an imported member is listed in ``__all__``, it will be
|
||||||
|
documented regardless of the value of ``autosummary_imported_members``. To
|
||||||
|
match the behaviour of ``from module import *``, set
|
||||||
|
``autosummary_ignore_module_all`` to False and
|
||||||
|
``autosummary_imported_members`` to True.
|
||||||
|
|
||||||
|
.. versionadded:: 4.4
|
||||||
|
|
||||||
.. confval:: autosummary_filename_map
|
.. confval:: autosummary_filename_map
|
||||||
|
|
||||||
A dict mapping object names to filenames. This is necessary to avoid
|
A dict mapping object names to filenames. This is necessary to avoid
|
||||||
|
@ -826,5 +826,6 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
app.add_config_value('autosummary_mock_imports',
|
app.add_config_value('autosummary_mock_imports',
|
||||||
lambda config: config.autodoc_mock_imports, 'env')
|
lambda config: config.autodoc_mock_imports, 'env')
|
||||||
app.add_config_value('autosummary_imported_members', [], False, [bool])
|
app.add_config_value('autosummary_imported_members', [], False, [bool])
|
||||||
|
app.add_config_value('autosummary_ignore_module_all', True, 'env', bool)
|
||||||
|
|
||||||
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
|
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
|
||||||
|
@ -28,7 +28,7 @@ import sys
|
|||||||
import warnings
|
import warnings
|
||||||
from gettext import NullTranslations
|
from gettext import NullTranslations
|
||||||
from os import path
|
from os import path
|
||||||
from typing import Any, Dict, List, NamedTuple, Set, Tuple, Type, Union
|
from typing import Any, Dict, List, NamedTuple, Sequence, Set, Tuple, Type, Union
|
||||||
|
|
||||||
from jinja2 import TemplateNotFound
|
from jinja2 import TemplateNotFound
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
@ -46,7 +46,7 @@ from sphinx.locale import __
|
|||||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||||
from sphinx.registry import SphinxComponentRegistry
|
from sphinx.registry import SphinxComponentRegistry
|
||||||
from sphinx.util import logging, rst, split_full_qualified_name
|
from sphinx.util import logging, rst, split_full_qualified_name
|
||||||
from sphinx.util.inspect import safe_getattr
|
from sphinx.util.inspect import getall, safe_getattr
|
||||||
from sphinx.util.osutil import ensuredir
|
from sphinx.util.osutil import ensuredir
|
||||||
from sphinx.util.template import SphinxTemplateLoader
|
from sphinx.util.template import SphinxTemplateLoader
|
||||||
|
|
||||||
@ -68,6 +68,7 @@ class DummyApplication:
|
|||||||
|
|
||||||
self.config.add('autosummary_context', {}, True, None)
|
self.config.add('autosummary_context', {}, True, None)
|
||||||
self.config.add('autosummary_filename_map', {}, True, None)
|
self.config.add('autosummary_filename_map', {}, True, None)
|
||||||
|
self.config.add('autosummary_ignore_module_all', True, 'env', bool)
|
||||||
self.config.init_values()
|
self.config.init_values()
|
||||||
|
|
||||||
def emit_firstresult(self, *args: Any) -> None:
|
def emit_firstresult(self, *args: Any) -> None:
|
||||||
@ -192,7 +193,7 @@ class ModuleScanner:
|
|||||||
|
|
||||||
def scan(self, imported_members: bool) -> List[str]:
|
def scan(self, imported_members: bool) -> List[str]:
|
||||||
members = []
|
members = []
|
||||||
for name in dir(self.object):
|
for name in members_of(self.object, self.app.config):
|
||||||
try:
|
try:
|
||||||
value = safe_getattr(self.object, name)
|
value = safe_getattr(self.object, name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -212,16 +213,31 @@ class ModuleScanner:
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
imported = False
|
imported = False
|
||||||
|
|
||||||
|
respect_module_all = not self.app.config.autosummary_ignore_module_all
|
||||||
if imported_members:
|
if imported_members:
|
||||||
# list all members up
|
# list all members up
|
||||||
members.append(name)
|
members.append(name)
|
||||||
elif imported is False:
|
elif imported is False:
|
||||||
# list not-imported members up
|
# list not-imported members
|
||||||
|
members.append(name)
|
||||||
|
elif '__all__' in dir(self.object) and respect_module_all:
|
||||||
|
# list members that have __all__ set
|
||||||
members.append(name)
|
members.append(name)
|
||||||
|
|
||||||
return members
|
return members
|
||||||
|
|
||||||
|
|
||||||
|
def members_of(obj: Any, conf: Config) -> Sequence[str]:
|
||||||
|
"""Get the members of ``obj``, possibly ignoring the ``__all__`` module attribute
|
||||||
|
|
||||||
|
Follows the ``conf.autosummary_ignore_module_all`` setting."""
|
||||||
|
|
||||||
|
if conf.autosummary_ignore_module_all:
|
||||||
|
return dir(obj)
|
||||||
|
else:
|
||||||
|
return getall(obj) or dir(obj)
|
||||||
|
|
||||||
|
|
||||||
def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||||
template: AutosummaryRenderer, template_name: str,
|
template: AutosummaryRenderer, template_name: str,
|
||||||
imported_members: bool, app: Any,
|
imported_members: bool, app: Any,
|
||||||
@ -245,7 +261,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
|
|
||||||
def get_module_members(obj: Any) -> Dict[str, Any]:
|
def get_module_members(obj: Any) -> Dict[str, Any]:
|
||||||
members = {}
|
members = {}
|
||||||
for name in dir(obj):
|
for name in members_of(obj, app.config):
|
||||||
try:
|
try:
|
||||||
members[name] = safe_getattr(obj, name)
|
members[name] = safe_getattr(obj, name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -630,6 +646,10 @@ The format of the autosummary directive is documented in the
|
|||||||
dest='imported_members', default=False,
|
dest='imported_members', default=False,
|
||||||
help=__('document imported members (default: '
|
help=__('document imported members (default: '
|
||||||
'%(default)s)'))
|
'%(default)s)'))
|
||||||
|
parser.add_argument('-a', '--respect-module-all', action='store_true',
|
||||||
|
dest='respect_module_all', default=False,
|
||||||
|
help=__('document exactly the members in module __all__ attribute. '
|
||||||
|
'(default: %(default)s)'))
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -646,6 +666,7 @@ def main(argv: List[str] = sys.argv[1:]) -> None:
|
|||||||
|
|
||||||
if args.templates:
|
if args.templates:
|
||||||
app.config.templates_path.append(path.abspath(args.templates))
|
app.config.templates_path.append(path.abspath(args.templates))
|
||||||
|
app.config.autosummary_ignore_module_all = not args.respect_module_all # type: ignore
|
||||||
|
|
||||||
generate_autosummary_docs(args.source_file, args.output_dir,
|
generate_autosummary_docs(args.source_file, args.output_dir,
|
||||||
'.' + args.suffix,
|
'.' + args.suffix,
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
from os import path # NOQA
|
from os import path # NOQA
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"CONSTANT1",
|
||||||
|
"Exc",
|
||||||
|
"Foo",
|
||||||
|
"_Baz",
|
||||||
|
"bar",
|
||||||
|
"qux",
|
||||||
|
"path",
|
||||||
|
]
|
||||||
|
|
||||||
#: module variable
|
#: module variable
|
||||||
CONSTANT1 = None
|
CONSTANT1 = None
|
||||||
CONSTANT2 = None
|
CONSTANT2 = None
|
||||||
@ -48,3 +58,5 @@ class _Exc(Exception):
|
|||||||
|
|
||||||
#: a module-level attribute
|
#: a module-level attribute
|
||||||
qux = 2
|
qux = 2
|
||||||
|
#: a module-level attribute that has been excluded from __all__
|
||||||
|
quuz = 2
|
||||||
|
@ -216,14 +216,42 @@ def test_autosummary_generate_content_for_module(app):
|
|||||||
|
|
||||||
context = template.render.call_args[0][1]
|
context = template.render.call_args[0][1]
|
||||||
assert context['members'] == ['CONSTANT1', 'CONSTANT2', 'Exc', 'Foo', '_Baz', '_Exc',
|
assert context['members'] == ['CONSTANT1', 'CONSTANT2', 'Exc', 'Foo', '_Baz', '_Exc',
|
||||||
'__builtins__', '__cached__', '__doc__', '__file__',
|
'__all__', '__builtins__', '__cached__', '__doc__',
|
||||||
'__name__', '__package__', '_quux', 'bar', 'qux']
|
'__file__', '__name__', '__package__', '_quux', 'bar',
|
||||||
|
'quuz', 'qux']
|
||||||
assert context['functions'] == ['bar']
|
assert context['functions'] == ['bar']
|
||||||
assert context['all_functions'] == ['_quux', 'bar']
|
assert context['all_functions'] == ['_quux', 'bar']
|
||||||
assert context['classes'] == ['Foo']
|
assert context['classes'] == ['Foo']
|
||||||
assert context['all_classes'] == ['Foo', '_Baz']
|
assert context['all_classes'] == ['Foo', '_Baz']
|
||||||
assert context['exceptions'] == ['Exc']
|
assert context['exceptions'] == ['Exc']
|
||||||
assert context['all_exceptions'] == ['Exc', '_Exc']
|
assert context['all_exceptions'] == ['Exc', '_Exc']
|
||||||
|
assert context['attributes'] == ['CONSTANT1', 'qux', 'quuz']
|
||||||
|
assert context['all_attributes'] == ['CONSTANT1', 'qux', 'quuz']
|
||||||
|
assert context['fullname'] == 'autosummary_dummy_module'
|
||||||
|
assert context['module'] == 'autosummary_dummy_module'
|
||||||
|
assert context['objname'] == ''
|
||||||
|
assert context['name'] == ''
|
||||||
|
assert context['objtype'] == 'module'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx(testroot='ext-autosummary')
|
||||||
|
def test_autosummary_generate_content_for_module___all__(app):
|
||||||
|
import autosummary_dummy_module
|
||||||
|
template = Mock()
|
||||||
|
app.config.autosummary_ignore_module_all = False
|
||||||
|
|
||||||
|
generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None,
|
||||||
|
template, None, False, app, False, {})
|
||||||
|
assert template.render.call_args[0][0] == 'module'
|
||||||
|
|
||||||
|
context = template.render.call_args[0][1]
|
||||||
|
assert context['members'] == ['CONSTANT1', 'Exc', 'Foo', '_Baz', 'bar', 'qux', 'path']
|
||||||
|
assert context['functions'] == ['bar']
|
||||||
|
assert context['all_functions'] == ['bar']
|
||||||
|
assert context['classes'] == ['Foo']
|
||||||
|
assert context['all_classes'] == ['Foo', '_Baz']
|
||||||
|
assert context['exceptions'] == ['Exc']
|
||||||
|
assert context['all_exceptions'] == ['Exc']
|
||||||
assert context['attributes'] == ['CONSTANT1', 'qux']
|
assert context['attributes'] == ['CONSTANT1', 'qux']
|
||||||
assert context['all_attributes'] == ['CONSTANT1', 'qux']
|
assert context['all_attributes'] == ['CONSTANT1', 'qux']
|
||||||
assert context['fullname'] == 'autosummary_dummy_module'
|
assert context['fullname'] == 'autosummary_dummy_module'
|
||||||
@ -246,9 +274,9 @@ def test_autosummary_generate_content_for_module_skipped(app):
|
|||||||
generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None,
|
generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None,
|
||||||
template, None, False, app, False, {})
|
template, None, False, app, False, {})
|
||||||
context = template.render.call_args[0][1]
|
context = template.render.call_args[0][1]
|
||||||
assert context['members'] == ['CONSTANT1', 'CONSTANT2', '_Baz', '_Exc', '__builtins__',
|
assert context['members'] == ['CONSTANT1', 'CONSTANT2', '_Baz', '_Exc', '__all__',
|
||||||
'__cached__', '__doc__', '__file__', '__name__',
|
'__builtins__', '__cached__', '__doc__', '__file__',
|
||||||
'__package__', '_quux', 'qux']
|
'__name__', '__package__', '_quux', 'quuz', 'qux']
|
||||||
assert context['functions'] == []
|
assert context['functions'] == []
|
||||||
assert context['classes'] == []
|
assert context['classes'] == []
|
||||||
assert context['exceptions'] == []
|
assert context['exceptions'] == []
|
||||||
@ -265,17 +293,17 @@ def test_autosummary_generate_content_for_module_imported_members(app):
|
|||||||
|
|
||||||
context = template.render.call_args[0][1]
|
context = template.render.call_args[0][1]
|
||||||
assert context['members'] == ['CONSTANT1', 'CONSTANT2', 'Exc', 'Foo', 'Union', '_Baz',
|
assert context['members'] == ['CONSTANT1', 'CONSTANT2', 'Exc', 'Foo', 'Union', '_Baz',
|
||||||
'_Exc', '__builtins__', '__cached__', '__doc__',
|
'_Exc', '__all__', '__builtins__', '__cached__', '__doc__',
|
||||||
'__file__', '__loader__', '__name__', '__package__',
|
'__file__', '__loader__', '__name__', '__package__',
|
||||||
'__spec__', '_quux', 'bar', 'path', 'qux']
|
'__spec__', '_quux', 'bar', 'path', 'quuz', 'qux']
|
||||||
assert context['functions'] == ['bar']
|
assert context['functions'] == ['bar']
|
||||||
assert context['all_functions'] == ['_quux', 'bar']
|
assert context['all_functions'] == ['_quux', 'bar']
|
||||||
assert context['classes'] == ['Foo']
|
assert context['classes'] == ['Foo']
|
||||||
assert context['all_classes'] == ['Foo', '_Baz']
|
assert context['all_classes'] == ['Foo', '_Baz']
|
||||||
assert context['exceptions'] == ['Exc']
|
assert context['exceptions'] == ['Exc']
|
||||||
assert context['all_exceptions'] == ['Exc', '_Exc']
|
assert context['all_exceptions'] == ['Exc', '_Exc']
|
||||||
assert context['attributes'] == ['CONSTANT1', 'qux']
|
assert context['attributes'] == ['CONSTANT1', 'qux', 'quuz']
|
||||||
assert context['all_attributes'] == ['CONSTANT1', 'qux']
|
assert context['all_attributes'] == ['CONSTANT1', 'qux', 'quuz']
|
||||||
assert context['fullname'] == 'autosummary_dummy_module'
|
assert context['fullname'] == 'autosummary_dummy_module'
|
||||||
assert context['module'] == 'autosummary_dummy_module'
|
assert context['module'] == 'autosummary_dummy_module'
|
||||||
assert context['objname'] == ''
|
assert context['objname'] == ''
|
||||||
@ -313,6 +341,7 @@ def test_autosummary_generate(app, status, warning):
|
|||||||
assert doctree[3][0][0][2][5].astext() == 'autosummary_dummy_module.qux\n\na module-level attribute'
|
assert doctree[3][0][0][2][5].astext() == 'autosummary_dummy_module.qux\n\na module-level attribute'
|
||||||
|
|
||||||
module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text()
|
module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text()
|
||||||
|
|
||||||
assert (' .. autosummary::\n'
|
assert (' .. autosummary::\n'
|
||||||
' \n'
|
' \n'
|
||||||
' Foo\n'
|
' Foo\n'
|
||||||
@ -321,6 +350,7 @@ def test_autosummary_generate(app, status, warning):
|
|||||||
' \n'
|
' \n'
|
||||||
' CONSTANT1\n'
|
' CONSTANT1\n'
|
||||||
' qux\n'
|
' qux\n'
|
||||||
|
' quuz\n'
|
||||||
' \n' in module)
|
' \n' in module)
|
||||||
|
|
||||||
Foo = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.rst').read_text()
|
Foo = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.rst').read_text()
|
||||||
|
Loading…
Reference in New Issue
Block a user