mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Close #8119: autodoc: Control visibility of module member not in __all__
This allows `autodoc-skip-member` handlers to determine whether a member not included in `__all__` attribute of the module should be documented or not.
This commit is contained in:
parent
1f88beb2b4
commit
9f0f34cbda
4
CHANGES
4
CHANGES
@ -13,6 +13,10 @@ Deprecated
|
|||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
* #8119: autodoc: Allow to determine whether a member not included in
|
||||||
|
``__all__`` attribute of the module should be documented or not via
|
||||||
|
:event:`autodoc-skip-member` event
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -272,12 +272,13 @@ class ObjectMember(tuple):
|
|||||||
interface.
|
interface.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, name: str, obj: Any) -> Any:
|
def __new__(cls, name: str, obj: Any, **kwargs: Any) -> Any:
|
||||||
return super().__new__(cls, (name, obj)) # type: ignore
|
return super().__new__(cls, (name, obj)) # type: ignore
|
||||||
|
|
||||||
def __init__(self, name: str, obj: Any) -> None:
|
def __init__(self, name: str, obj: Any, skipped: bool = False) -> None:
|
||||||
self.__name__ = name
|
self.__name__ = name
|
||||||
self.object = obj
|
self.object = obj
|
||||||
|
self.skipped = skipped
|
||||||
|
|
||||||
|
|
||||||
ObjectMembers = Union[List[ObjectMember], List[Tuple[str, Any]]]
|
ObjectMembers = Union[List[ObjectMember], List[Tuple[str, Any]]]
|
||||||
@ -670,7 +671,8 @@ class Documenter:
|
|||||||
attr_docs = {}
|
attr_docs = {}
|
||||||
|
|
||||||
# process members and determine which to skip
|
# process members and determine which to skip
|
||||||
for (membername, member) in members:
|
for obj in members:
|
||||||
|
membername, member = obj
|
||||||
# if isattr is True, the member is documented as an attribute
|
# if isattr is True, the member is documented as an attribute
|
||||||
if member is INSTANCEATTR:
|
if member is INSTANCEATTR:
|
||||||
isattr = True
|
isattr = True
|
||||||
@ -747,6 +749,10 @@ class Documenter:
|
|||||||
# ignore undocumented members if :undoc-members: is not given
|
# ignore undocumented members if :undoc-members: is not given
|
||||||
keep = has_doc or self.options.undoc_members
|
keep = has_doc or self.options.undoc_members
|
||||||
|
|
||||||
|
if isinstance(obj, ObjectMember) and obj.skipped:
|
||||||
|
# forcedly skipped member (ex. a module attribute not defined in __all__)
|
||||||
|
keep = False
|
||||||
|
|
||||||
# give the user a chance to decide whether this member
|
# give the user a chance to decide whether this member
|
||||||
# should be skipped
|
# should be skipped
|
||||||
if self.env.app:
|
if self.env.app:
|
||||||
@ -1010,26 +1016,33 @@ class ModuleDocumenter(Documenter):
|
|||||||
|
|
||||||
def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]:
|
def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]:
|
||||||
if want_all:
|
if want_all:
|
||||||
if self.__all__:
|
members = get_module_members(self.object)
|
||||||
memberlist = self.__all__
|
if not self.__all__:
|
||||||
else:
|
|
||||||
# for implicit module members, check __module__ to avoid
|
# for implicit module members, check __module__ to avoid
|
||||||
# documenting imported objects
|
# documenting imported objects
|
||||||
return True, get_module_members(self.object)
|
return True, members
|
||||||
|
else:
|
||||||
|
ret = []
|
||||||
|
for name, value in members:
|
||||||
|
if name in self.__all__:
|
||||||
|
ret.append(ObjectMember(name, value))
|
||||||
|
else:
|
||||||
|
ret.append(ObjectMember(name, value, skipped=True))
|
||||||
|
|
||||||
|
return False, ret
|
||||||
else:
|
else:
|
||||||
memberlist = self.options.members or []
|
memberlist = self.options.members or []
|
||||||
ret = []
|
ret = []
|
||||||
for mname in memberlist:
|
for name in memberlist:
|
||||||
try:
|
try:
|
||||||
ret.append((mname, safe_getattr(self.object, mname)))
|
value = safe_getattr(self.object, name)
|
||||||
except AttributeError:
|
ret.append(ObjectMember(name, value))
|
||||||
logger.warning(
|
except AttributeError:
|
||||||
__('missing attribute mentioned in :members: or __all__: '
|
logger.warning(__('missing attribute mentioned in :members: option: '
|
||||||
'module %s, attribute %s') %
|
'module %s, attribute %s') %
|
||||||
(safe_getattr(self.object, '__name__', '???'), mname),
|
(safe_getattr(self.object, '__name__', '???'), name),
|
||||||
type='autodoc'
|
type='autodoc')
|
||||||
)
|
return False, ret
|
||||||
return False, ret
|
|
||||||
|
|
||||||
def sort_members(self, documenters: List[Tuple["Documenter", bool]],
|
def sort_members(self, documenters: List[Tuple["Documenter", bool]],
|
||||||
order: str) -> List[Tuple["Documenter", bool]]:
|
order: str) -> List[Tuple["Documenter", bool]]:
|
||||||
|
@ -80,3 +80,28 @@ def test_between_exclude(app):
|
|||||||
' third line',
|
' third line',
|
||||||
'',
|
'',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||||
|
def test_skip_module_member(app):
|
||||||
|
def autodoc_skip_member(app, what, name, obj, skip, options):
|
||||||
|
if name == "Class":
|
||||||
|
return True # Skip "Class" class in __all__
|
||||||
|
elif name == "raises":
|
||||||
|
return False # Show "raises()" function (not in __all__)
|
||||||
|
|
||||||
|
app.connect('autodoc-skip-member', autodoc_skip_member)
|
||||||
|
|
||||||
|
options = {"members": None}
|
||||||
|
actual = do_autodoc(app, 'module', 'target', options)
|
||||||
|
assert list(actual) == [
|
||||||
|
'',
|
||||||
|
'.. py:module:: target',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:function:: raises(exc, func, *args, **kwds)',
|
||||||
|
' :module: target',
|
||||||
|
'',
|
||||||
|
' Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*.',
|
||||||
|
'',
|
||||||
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user