Fix #9283: autodoc: failed to build doc for attribute not commented

Autoattribute directive should check the existence of instance attribute
that is defined inside __init__() but not having comments before
accessing it.
This commit is contained in:
Takeshi KOMIYA 2021-05-30 13:50:07 +09:00
parent 2809b30c17
commit 9a9433e403
4 changed files with 41 additions and 0 deletions

View File

@ -55,6 +55,8 @@ Bugs fixed
undocumented
* #9185: autodoc: typehints for overloaded functions and methods are inaccurate
* #9250: autodoc: The inherited method not having docstring is wrongly parsed
* #9283: autodoc: autoattribute directive failed to generate document for an
attribute not having any comment
* #9270: html theme : pyramid theme generates incorrect logo links
* #9217: manpage: The name of manpage directory that is generated by
:confval:`man_make_section_directory` is not correct

View File

@ -2356,9 +2356,29 @@ class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
# An instance variable defined in __init__().
if self.get_attribute_comment(parent, self.objpath[-1]): # type: ignore
return True
elif self.is_runtime_instance_attribute_not_commented(parent):
return True
else:
return False
def is_runtime_instance_attribute_not_commented(self, parent: Any) -> bool:
"""Check the subject is an attribute defined in __init__() without comment."""
for cls in inspect.getmro(parent):
try:
module = safe_getattr(cls, '__module__')
qualname = safe_getattr(cls, '__qualname__')
analyzer = ModuleAnalyzer.for_module(module)
analyzer.analyze()
if qualname and self.objpath:
key = '.'.join([qualname, self.objpath[-1]])
if key in analyzer.tagorder:
return True
except (AttributeError, PycodeError):
pass
return None
def import_object(self, raiseerror: bool = False) -> bool:
"""Check the existence of runtime instance attribute when failed to import the
attribute."""
@ -2389,6 +2409,13 @@ class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
return (self.object is self.RUNTIME_INSTANCE_ATTRIBUTE or
super().should_suppress_value_header())
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
if (self.object is self.RUNTIME_INSTANCE_ATTRIBUTE and
self.is_runtime_instance_attribute_not_commented(self.parent)):
return None
else:
return super().get_doc(ignore) # type: ignore
class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
"""

View File

@ -8,3 +8,4 @@ class Bar(Foo):
def __init__(self):
self.attr2 = None #: docstring bar
self.attr3 = None #: docstring bar
self.attr4 = None

View File

@ -100,6 +100,17 @@ def test_autoattribute_instance_variable_in_alias(app):
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoattribute_instance_variable_without_comment(app):
actual = do_autodoc(app, 'attribute', 'target.instance_variable.Bar.attr4')
assert list(actual) == [
'',
'.. py:attribute:: Bar.attr4',
' :module: target.instance_variable',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoattribute_slots_variable_list(app):
actual = do_autodoc(app, 'attribute', 'target.slots.Foo.attr')