mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Fix #8541: autodoc_type_aliases doesn't work for the instance attrs
So far, autodoc obtains type annotations of instance attributes by ModuleAnalyzer directly. As a result, autodoc_type_aliases are ignored for these variables. This goes to merge type annotations from the class itself and ModuleAnalyzer's, and get type annotations using `typing.get_type_hints()` to apply autodoc_type_aliases.
This commit is contained in:
2
CHANGES
2
CHANGES
@@ -71,6 +71,8 @@ Bugs fixed
|
||||
attribute in alias class
|
||||
* #8452: autodoc: autodoc_type_aliases doesn't work when autodoc_typehints is
|
||||
set to "description"
|
||||
* #8541: autodoc: autodoc_type_aliases doesn't work for the type annotation to
|
||||
instance attributes
|
||||
* #8460: autodoc: autodata and autoattribute directives do not display type
|
||||
information of TypeVars
|
||||
* #8493: autodoc: references to builtins not working in class aliases
|
||||
|
||||
@@ -1843,6 +1843,26 @@ class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
|
||||
) -> bool:
|
||||
return isinstance(parent, ModuleDocumenter) and isattr
|
||||
|
||||
def update_annotations(self, parent: Any) -> None:
|
||||
"""Update __annotations__ to support type_comment and so on."""
|
||||
try:
|
||||
annotations = inspect.getannotations(parent)
|
||||
|
||||
analyzer = ModuleAnalyzer.for_module(self.modname)
|
||||
analyzer.analyze()
|
||||
for (classname, attrname) in analyzer.annotations:
|
||||
if classname == '' and attrname not in annotations:
|
||||
annotations[attrname] = analyzer.annotations[classname, attrname] # type: ignore # NOQA
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
ret = super().import_object(raiseerror)
|
||||
if self.parent:
|
||||
self.update_annotations(self.parent)
|
||||
|
||||
return ret
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
super().add_directive_header(sig)
|
||||
sourcename = self.get_sourcename()
|
||||
@@ -1857,11 +1877,6 @@ class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
|
||||
if self.objpath[-1] in annotations:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
else:
|
||||
key = ('.'.join(self.objpath[:-1]), self.objpath[-1])
|
||||
if self.analyzer and key in self.analyzer.annotations:
|
||||
self.add_line(' :type: ' + self.analyzer.annotations[key],
|
||||
sourcename)
|
||||
|
||||
try:
|
||||
if self.options.no_value or self.should_suppress_value_header():
|
||||
@@ -2259,6 +2274,26 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
|
||||
|
||||
return False
|
||||
|
||||
def update_annotations(self, parent: Any) -> None:
|
||||
"""Update __annotations__ to support type_comment and so on."""
|
||||
try:
|
||||
annotations = inspect.getannotations(parent)
|
||||
|
||||
for cls in inspect.getmro(parent):
|
||||
try:
|
||||
module = safe_getattr(cls, '__module__')
|
||||
qualname = safe_getattr(cls, '__qualname__')
|
||||
|
||||
analyzer = ModuleAnalyzer.for_module(module)
|
||||
analyzer.analyze()
|
||||
for (classname, attrname) in analyzer.annotations:
|
||||
if classname == qualname and attrname not in annotations:
|
||||
annotations[attrname] = analyzer.annotations[classname, attrname] # type: ignore # NOQA
|
||||
except (AttributeError, PycodeError):
|
||||
pass
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
try:
|
||||
ret = super().import_object(raiseerror=True)
|
||||
@@ -2275,6 +2310,9 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
|
||||
self.env.note_reread()
|
||||
ret = False
|
||||
|
||||
if self.parent:
|
||||
self.update_annotations(self.parent)
|
||||
|
||||
return ret
|
||||
|
||||
def get_real_modname(self) -> str:
|
||||
@@ -2294,16 +2332,6 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
|
||||
if self.objpath[-1] in annotations:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
else:
|
||||
try:
|
||||
qualname = safe_getattr(self.parent, '__qualname__',
|
||||
'.'.join(self.objpath[:-1]))
|
||||
key = (qualname, self.objpath[-1])
|
||||
if self.analyzer and key in self.analyzer.annotations:
|
||||
self.add_line(' :type: ' + self.analyzer.annotations[key],
|
||||
sourcename)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
if (self.object is INSTANCEATTR or self.options.no_value or
|
||||
|
||||
@@ -7,6 +7,9 @@ myint = int
|
||||
#: docstring
|
||||
variable: myint
|
||||
|
||||
#: docstring
|
||||
variable2 = None # type: myint
|
||||
|
||||
|
||||
def sum(x: myint, y: myint) -> myint:
|
||||
"""docstring"""
|
||||
@@ -32,4 +35,7 @@ class Foo:
|
||||
"""docstring"""
|
||||
|
||||
#: docstring
|
||||
attr: myint
|
||||
attr1: myint
|
||||
|
||||
def __init__(self):
|
||||
self.attr2: myint = None #: docstring
|
||||
|
||||
@@ -1675,9 +1675,25 @@ def test_autodoc_typed_inherited_instance_variables(app):
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr3',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
' :value: 0',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr4',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr5',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr6',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Derived.attr7',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
|
||||
@@ -707,7 +707,14 @@ def test_autodoc_type_aliases(app):
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr',
|
||||
' .. py:attribute:: Foo.attr1',
|
||||
' :module: target.annotations',
|
||||
' :type: int',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr2',
|
||||
' :module: target.annotations',
|
||||
' :type: int',
|
||||
'',
|
||||
@@ -733,6 +740,14 @@ def test_autodoc_type_aliases(app):
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: variable2',
|
||||
' :module: target.annotations',
|
||||
' :type: int',
|
||||
' :value: None',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
]
|
||||
|
||||
# define aliases
|
||||
@@ -749,7 +764,14 @@ def test_autodoc_type_aliases(app):
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr',
|
||||
' .. py:attribute:: Foo.attr1',
|
||||
' :module: target.annotations',
|
||||
' :type: myint',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr2',
|
||||
' :module: target.annotations',
|
||||
' :type: myint',
|
||||
'',
|
||||
@@ -775,6 +797,14 @@ def test_autodoc_type_aliases(app):
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: variable2',
|
||||
' :module: target.annotations',
|
||||
' :type: myint',
|
||||
' :value: None',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user