Skip to content

Commit

Permalink
Fix sphinx-doc#9283: autodoc: failed to build doc for attribute not c…
Browse files Browse the repository at this point in the history
…ommented

Autoattribute directive should check the existence of instance attribute
that is defined inside __init__() but not having comments before
accessing it.
  • Loading branch information
tk0miya committed May 30, 2021
1 parent 2809b30 commit 7462f0a
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions sphinx/ext/autodoc/__init__.py
Expand Up @@ -2356,9 +2356,29 @@ def is_runtime_instance_attribute(self, parent: Any) -> bool:
# 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, self.objpath[-1]):
return True
else:
return False

def is_runtime_instance_attribute_not_commented(self, parent: Any, attrname: str) -> 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, attrname])
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."""
Expand Down Expand Up @@ -2389,6 +2409,12 @@ def should_suppress_value_header(self) -> bool:
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.is_runtime_instance_attribute_not_commented(self.parent, self.objpath[-1]):
return None
else:
return super().get_doc(ignore) # type: ignore


class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
"""
Expand Down
1 change: 1 addition & 0 deletions tests/roots/test-ext-autodoc/target/instance_variable.py
Expand Up @@ -8,3 +8,4 @@ class Bar(Foo):
def __init__(self):
self.attr2 = None #: docstring bar
self.attr3 = None #: docstring bar
self.attr4 = None
11 changes: 11 additions & 0 deletions tests/test_ext_autodoc_autoattribute.py
Expand Up @@ -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')
Expand Down

0 comments on commit 7462f0a

Please sign in to comment.