Skip to content

Commit

Permalink
Fix sphinx-doc#8567: autodoc: Instance attributes are incorrectly add…
Browse files Browse the repository at this point in the history
…ed to Parent class

The instance attributes on subclasses are shown on the document of
parent class unexpectedly because of autodoc modifies `__annotations__`
in place.  This fix creates a copy of `__annotations__` attribute and
attach it to the subclass.
  • Loading branch information
tk0miya committed Dec 21, 2020
1 parent 31cad2e commit 70bb226
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -19,6 +19,7 @@ Bugs fixed
* #8559: autodoc: AttributeError is raised when using forward-reference type
annotations
* #8568: autodoc: TypeError is raised on checking slots attribute
* #8567: autodoc: Instance attributes are incorrectly added to Parent class

Testing
--------
Expand Down
13 changes: 9 additions & 4 deletions sphinx/ext/autodoc/__init__.py
Expand Up @@ -1856,13 +1856,14 @@ def can_document_member(cls, member: Any, membername: str, isattr: bool, parent:
def update_annotations(self, parent: Any) -> None:
"""Update __annotations__ to support type_comment and so on."""
try:
annotations = inspect.getannotations(parent)
annotations = dict(inspect.getannotations(parent))
parent.__annotations__ = annotations

analyzer = ModuleAnalyzer.for_module(self.modname)
analyzer.analyze()
for (classname, attrname), annotation in analyzer.annotations.items():
if classname == '' and attrname not in annotations:
annotations[attrname] = annotation # type: ignore
annotations[attrname] = annotation
except AttributeError:
pass

Expand Down Expand Up @@ -2292,7 +2293,8 @@ def isinstanceattribute(self) -> bool:
def update_annotations(self, parent: Any) -> None:
"""Update __annotations__ to support type_comment and so on."""
try:
annotations = inspect.getannotations(parent)
annotations = dict(inspect.getannotations(parent))
parent.__annotations__ = annotations

for cls in inspect.getmro(parent):
try:
Expand All @@ -2303,11 +2305,14 @@ def update_annotations(self, parent: Any) -> None:
analyzer.analyze()
for (classname, attrname), annotation in analyzer.annotations.items():
if classname == qualname and attrname not in annotations:
annotations[attrname] = annotation # type: ignore
annotations[attrname] = annotation
except (AttributeError, PycodeError):
pass
except AttributeError:
pass
except TypeError:
# Failed to set __annotations__ (built-in, extensions, etc.)
pass

def import_object(self, raiseerror: bool = False) -> bool:
try:
Expand Down
1 change: 1 addition & 0 deletions tests/test_ext_autodoc.py
Expand Up @@ -690,6 +690,7 @@ def test_autodoc_special_members(app):
actual = do_autodoc(app, 'class', 'target.Class', options)
assert list(filter(lambda l: '::' in l, actual)) == [
'.. py:class:: Class(arg)',
' .. py:attribute:: Class.__annotations__',
' .. py:attribute:: Class.__dict__',
' .. py:method:: Class.__init__(arg)',
' .. py:attribute:: Class.__module__',
Expand Down

0 comments on commit 70bb226

Please sign in to comment.