mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #8042 from tk0miya/8041_ivar_on_superclass_not_shown
Fix #8041: autodoc: An ivar on super class is not shown unexpectedly
This commit is contained in:
commit
697dff31ab
2
CHANGES
2
CHANGES
@ -71,6 +71,8 @@ Bugs fixed
|
||||
when ``:inherited-members:`` option given
|
||||
* #8032: autodoc: A type hint for the instance variable defined at parent class
|
||||
is not shown in the document of the derived class
|
||||
* #8041: autodoc: An annotated instance variable on super class is not
|
||||
documented when derived class has other annotated instance variables
|
||||
* #7839: autosummary: cannot handle umlauts in function names
|
||||
* #7865: autosummary: Failed to extract summary line when abbreviations found
|
||||
* #7866: autosummary: Failed to extract correct summary line when docstring
|
||||
|
@ -18,6 +18,7 @@ from types import ModuleType
|
||||
from typing import (
|
||||
Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union
|
||||
)
|
||||
from typing import get_type_hints
|
||||
|
||||
from docutils.statemachine import StringList
|
||||
|
||||
@ -1605,8 +1606,12 @@ class DataDocumenter(ModuleLevelDocumenter):
|
||||
sourcename = self.get_sourcename()
|
||||
if not self.options.annotation:
|
||||
# obtain annotation for this data
|
||||
annotations = getattr(self.parent, '__annotations__', {})
|
||||
if annotations and self.objpath[-1] in annotations:
|
||||
try:
|
||||
annotations = get_type_hints(self.parent)
|
||||
except TypeError:
|
||||
annotations = {}
|
||||
|
||||
if self.objpath[-1] in annotations:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
else:
|
||||
@ -1971,8 +1976,12 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
||||
sourcename = self.get_sourcename()
|
||||
if not self.options.annotation:
|
||||
# obtain type annotation for this attribute
|
||||
annotations = getattr(self.parent, '__annotations__', {})
|
||||
if annotations and self.objpath[-1] in annotations:
|
||||
try:
|
||||
annotations = get_type_hints(self.parent)
|
||||
except TypeError:
|
||||
annotations = {}
|
||||
|
||||
if self.objpath[-1] in annotations:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
else:
|
||||
|
@ -18,6 +18,10 @@ from sphinx.pycode import ModuleAnalyzer
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.inspect import isclass, isenumclass, safe_getattr
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # NOQA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -158,6 +162,24 @@ Attribute = NamedTuple('Attribute', [('name', str),
|
||||
('value', Any)])
|
||||
|
||||
|
||||
def _getmro(obj: Any) -> Tuple["Type", ...]:
|
||||
"""Get __mro__ from given *obj* safely."""
|
||||
__mro__ = safe_getattr(obj, '__mro__', None)
|
||||
if isinstance(__mro__, tuple):
|
||||
return __mro__
|
||||
else:
|
||||
return tuple()
|
||||
|
||||
|
||||
def _getannotations(obj: Any) -> Mapping[str, Any]:
|
||||
"""Get __annotations__ from given *obj* safely."""
|
||||
__annotations__ = safe_getattr(obj, '__annotations__', None)
|
||||
if isinstance(__annotations__, Mapping):
|
||||
return __annotations__
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable,
|
||||
analyzer: ModuleAnalyzer = None) -> Dict[str, Attribute]:
|
||||
"""Get members and attributes of target object."""
|
||||
@ -199,11 +221,11 @@ def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable,
|
||||
continue
|
||||
|
||||
# annotation only member (ex. attr: int)
|
||||
if hasattr(subject, '__annotations__') and isinstance(subject.__annotations__, Mapping):
|
||||
for name in subject.__annotations__:
|
||||
name = unmangle(subject, name)
|
||||
for i, cls in enumerate(_getmro(subject)):
|
||||
for name in _getannotations(cls):
|
||||
name = unmangle(cls, name)
|
||||
if name and name not in members:
|
||||
members[name] = Attribute(name, True, INSTANCEATTR)
|
||||
members[name] = Attribute(name, i == 0, INSTANCEATTR)
|
||||
|
||||
if analyzer:
|
||||
# append instance attributes (cf. self.attr1) if analyzer knows
|
||||
|
@ -28,4 +28,4 @@ class Class:
|
||||
|
||||
|
||||
class Derived(Class):
|
||||
pass
|
||||
attr7: int
|
||||
|
@ -1580,12 +1580,7 @@ def test_autodoc_typed_instance_variables(app):
|
||||
' :module: target.typed_vars',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr2',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.descr4',
|
||||
' .. py:attribute:: Derived.attr7',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
@ -1615,6 +1610,47 @@ def test_autodoc_typed_instance_variables(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 6), reason='py36+ is available since python3.6.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_typed_inherited_instance_variables(app):
|
||||
options = {"members": None,
|
||||
"undoc-members": True,
|
||||
"inherited-members": True}
|
||||
actual = do_autodoc(app, 'class', 'target.typed_vars.Derived', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Derived()',
|
||||
' :module: target.typed_vars',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr1',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
' :value: 0',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr2',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr3',
|
||||
' :module: target.typed_vars',
|
||||
' :value: 0',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr7',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.descr4',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_GenericAlias(app):
|
||||
options = {"members": None,
|
||||
|
Loading…
Reference in New Issue
Block a user