mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Autosummary: Extend `__all__
` members to template rendering (#10811)
When ``False``, the ``autosummary_ignore_module_all`` option adds members to the module's members entry that will be used for autodoc, but otherwise ignores it. As such, if a class is available in the ``__all__``, it won't be generated. This commit aims to extend the ``__all__`` handling not only to members, but also to corresponding attribute types (function, classes, exceptions, modules) The ``imported_members`` option is set to ``True`` if the object has an ``__all__`` member and ``autosummary_ignore_module_all`` is ``False``
This commit is contained in:
parent
52a099b7ec
commit
9299003d40
3
CHANGES
3
CHANGES
@ -27,6 +27,9 @@ Deprecated
|
|||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
* #10811: Autosummary: extend ``__all__`` to imported members for template rendering
|
||||||
|
when option ``autosummary_ignore_module_all`` is set to ``False``. Patch by
|
||||||
|
Clement Pinard
|
||||||
* #11147: Add a ``content_offset`` parameter to ``nested_parse_with_titles()``,
|
* #11147: Add a ``content_offset`` parameter to ``nested_parse_with_titles()``,
|
||||||
allowing for correct line numbers during nested parsing.
|
allowing for correct line numbers during nested parsing.
|
||||||
Patch by Jeremy Maitin-Shepard
|
Patch by Jeremy Maitin-Shepard
|
||||||
|
@ -300,9 +300,17 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
pass # give up if ModuleAnalyzer fails to parse code
|
pass # give up if ModuleAnalyzer fails to parse code
|
||||||
return public, attrs
|
return public, attrs
|
||||||
|
|
||||||
def get_modules(obj: Any) -> tuple[list[str], list[str]]:
|
def get_modules(
|
||||||
|
obj: Any,
|
||||||
|
skip: Sequence[str],
|
||||||
|
public_members: Sequence[str] | None = None) -> tuple[list[str], list[str]]:
|
||||||
items: list[str] = []
|
items: list[str] = []
|
||||||
|
public: list[str] = []
|
||||||
for _, modname, _ispkg in pkgutil.iter_modules(obj.__path__):
|
for _, modname, _ispkg in pkgutil.iter_modules(obj.__path__):
|
||||||
|
|
||||||
|
if modname in skip:
|
||||||
|
# module was overwritten in __init__.py, so not accessible
|
||||||
|
continue
|
||||||
fullname = name + '.' + modname
|
fullname = name + '.' + modname
|
||||||
try:
|
try:
|
||||||
module = import_module(fullname)
|
module = import_module(fullname)
|
||||||
@ -312,7 +320,12 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
items.append(fullname)
|
items.append(fullname)
|
||||||
public = [x for x in items if not x.split('.')[-1].startswith('_')]
|
if public_members is not None:
|
||||||
|
if modname in public_members:
|
||||||
|
public.append(fullname)
|
||||||
|
else:
|
||||||
|
if not modname.startswith('_'):
|
||||||
|
public.append(fullname)
|
||||||
return public, items
|
return public, items
|
||||||
|
|
||||||
ns: dict[str, Any] = {}
|
ns: dict[str, Any] = {}
|
||||||
@ -321,6 +334,10 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
if doc.objtype == 'module':
|
if doc.objtype == 'module':
|
||||||
scanner = ModuleScanner(app, obj)
|
scanner = ModuleScanner(app, obj)
|
||||||
ns['members'] = scanner.scan(imported_members)
|
ns['members'] = scanner.scan(imported_members)
|
||||||
|
|
||||||
|
respect_module_all = not app.config.autosummary_ignore_module_all
|
||||||
|
imported_members = imported_members or ('__all__' in dir(obj) and respect_module_all)
|
||||||
|
|
||||||
ns['functions'], ns['all_functions'] = \
|
ns['functions'], ns['all_functions'] = \
|
||||||
get_members(obj, {'function'}, imported=imported_members)
|
get_members(obj, {'function'}, imported=imported_members)
|
||||||
ns['classes'], ns['all_classes'] = \
|
ns['classes'], ns['all_classes'] = \
|
||||||
@ -331,7 +348,36 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
get_module_attrs(ns['members'])
|
get_module_attrs(ns['members'])
|
||||||
ispackage = hasattr(obj, '__path__')
|
ispackage = hasattr(obj, '__path__')
|
||||||
if ispackage and recursive:
|
if ispackage and recursive:
|
||||||
ns['modules'], ns['all_modules'] = get_modules(obj)
|
# Use members that are not modules as skip list, because it would then mean
|
||||||
|
# that module was overwritten in the package namespace
|
||||||
|
skip = (
|
||||||
|
ns["all_functions"]
|
||||||
|
+ ns["all_classes"]
|
||||||
|
+ ns["all_exceptions"]
|
||||||
|
+ ns["all_attributes"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# If respect_module_all and module has a __all__ attribute, first get
|
||||||
|
# modules that were explicitly imported. Next, find the rest with the
|
||||||
|
# get_modules method, but only put in "public" modules that are in the
|
||||||
|
# __all__ list
|
||||||
|
#
|
||||||
|
# Otherwise, use get_modules method normally
|
||||||
|
if respect_module_all and '__all__' in dir(obj):
|
||||||
|
imported_modules, all_imported_modules = \
|
||||||
|
get_members(obj, {'module'}, imported=True)
|
||||||
|
skip += all_imported_modules
|
||||||
|
imported_modules = [name + '.' + modname for modname in imported_modules]
|
||||||
|
all_imported_modules = \
|
||||||
|
[name + '.' + modname for modname in all_imported_modules]
|
||||||
|
public_members = getall(obj)
|
||||||
|
else:
|
||||||
|
imported_modules, all_imported_modules = [], []
|
||||||
|
public_members = None
|
||||||
|
|
||||||
|
modules, all_modules = get_modules(obj, skip=skip, public_members=public_members)
|
||||||
|
ns['modules'] = imported_modules + modules
|
||||||
|
ns["all_modules"] = all_imported_modules + all_modules
|
||||||
elif doc.objtype == 'class':
|
elif doc.objtype == 'class':
|
||||||
ns['members'] = dir(obj)
|
ns['members'] = dir(obj)
|
||||||
ns['inherited_members'] = \
|
ns['inherited_members'] = \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
test-ext-autosummary-mock_imports
|
test-ext-autosummary-imported_members
|
||||||
=================================
|
=====================================
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
:toctree: generated
|
:toctree: generated
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
from .autosummary_dummy_module import Bar, PublicBar, foo, public_foo
|
||||||
|
|
||||||
|
|
||||||
|
def baz():
|
||||||
|
"""Baz function"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def public_baz():
|
||||||
|
"""Public Baz function"""
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["PublicBar", "public_foo", "public_baz", "extra_dummy_module"]
|
@ -0,0 +1,20 @@
|
|||||||
|
class Bar:
|
||||||
|
"""Bar class"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PublicBar:
|
||||||
|
"""Public Bar class"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
"""Foo function"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def public_foo():
|
||||||
|
"""Public Foo function"""
|
||||||
|
pass
|
@ -0,0 +1,20 @@
|
|||||||
|
class Bar:
|
||||||
|
"""Bar class"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PublicBar:
|
||||||
|
"""Public Bar class"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
"""Foo function"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def public_foo():
|
||||||
|
"""Public Foo function"""
|
||||||
|
pass
|
8
tests/roots/test-ext-autosummary-module_all/conf.py
Normal file
8
tests/roots/test-ext-autosummary-module_all/conf.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
extensions = ['sphinx.ext.autosummary']
|
||||||
|
autosummary_generate = True
|
||||||
|
autosummary_ignore_module_all = False
|
8
tests/roots/test-ext-autosummary-module_all/index.rst
Normal file
8
tests/roots/test-ext-autosummary-module_all/index.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
test-ext-autosummary-module_all
|
||||||
|
===============================
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated
|
||||||
|
:recursive:
|
||||||
|
|
||||||
|
autosummary_dummy_package_all
|
@ -545,6 +545,30 @@ def test_autosummary_imported_members(app, status, warning):
|
|||||||
sys.modules.pop('autosummary_dummy_package', None)
|
sys.modules.pop('autosummary_dummy_package', None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-module_all')
|
||||||
|
def test_autosummary_module_all(app, status, warning):
|
||||||
|
try:
|
||||||
|
app.build()
|
||||||
|
# generated/foo is generated successfully
|
||||||
|
assert app.env.get_doctree('generated/autosummary_dummy_package_all')
|
||||||
|
module = (app.srcdir / 'generated' / 'autosummary_dummy_package_all.rst').read_text(encoding='utf8')
|
||||||
|
assert (' .. autosummary::\n'
|
||||||
|
' \n'
|
||||||
|
' PublicBar\n'
|
||||||
|
' \n' in module)
|
||||||
|
assert (' .. autosummary::\n'
|
||||||
|
' \n'
|
||||||
|
' public_foo\n'
|
||||||
|
' public_baz\n'
|
||||||
|
' \n' in module)
|
||||||
|
assert ('.. autosummary::\n'
|
||||||
|
' :toctree:\n'
|
||||||
|
' :recursive:\n\n'
|
||||||
|
' autosummary_dummy_package_all.extra_dummy_module\n\n' in module)
|
||||||
|
finally:
|
||||||
|
sys.modules.pop('autosummary_dummy_package_all', None)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx(testroot='ext-autodoc',
|
@pytest.mark.sphinx(testroot='ext-autodoc',
|
||||||
confoverrides={'extensions': ['sphinx.ext.autosummary']})
|
confoverrides={'extensions': ['sphinx.ext.autosummary']})
|
||||||
def test_generate_autosummary_docs_property(app):
|
def test_generate_autosummary_docs_property(app):
|
||||||
|
Loading…
Reference in New Issue
Block a user