From 92cb828f14afb61645ea807f456d9ba9f0f8d0e0 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 1 Feb 2020 13:38:34 +0900 Subject: [PATCH] autodoc: Support type_comment styled type annotation for variables --- sphinx/ext/autodoc/__init__.py | 5 ++++ sphinx/pycode/ast.py | 2 ++ sphinx/pycode/parser.py | 8 +++-- .../test-ext-autodoc/target/typed_vars.py | 9 ++++-- tests/test_autodoc.py | 30 ++++++++++++++++--- tests/test_pycode_parser.py | 10 +++++-- 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 3fcbf9a2e..f433ea88a 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1239,6 +1239,11 @@ class DataDocumenter(ModuleLevelDocumenter): 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: objrepr = object_description(self.object) diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index 155ae86d5..22207b715 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -38,6 +38,8 @@ def unparse(node: ast.AST) -> str: """Unparse an AST to string.""" if node is None: return None + elif isinstance(node, str): + return node elif isinstance(node, ast.Attribute): return "%s.%s" % (unparse(node.value), node.attr) elif isinstance(node, ast.Bytes): diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index 4ec1a844d..1f803e950 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -311,10 +311,12 @@ class VariableCommentPicker(ast.NodeVisitor): return # this assignment is not new definition! # record annotation - annotation = getattr(node, 'annotation', None) - if annotation: + if hasattr(node, 'annotation') and node.annotation: # type: ignore for varname in varnames: - self.add_variable_annotation(varname, annotation) + self.add_variable_annotation(varname, node.annotation) # type: ignore + elif hasattr(node, 'type_comment') and node.type_comment: + for varname in varnames: + self.add_variable_annotation(varname, node.type_comment) # type: ignore # check comments after assignment parser = AfterCommentParser([current_line[node.col_offset:]] + diff --git a/tests/roots/test-ext-autodoc/target/typed_vars.py b/tests/roots/test-ext-autodoc/target/typed_vars.py index 4a9a6f7b5..b0782787e 100644 --- a/tests/roots/test-ext-autodoc/target/typed_vars.py +++ b/tests/roots/test-ext-autodoc/target/typed_vars.py @@ -2,12 +2,17 @@ attr1: str = '' #: attr2 attr2: str +#: attr3 +attr3 = '' # type: str class Class: attr1: int = 0 attr2: int + attr3 = 0 # type: int def __init__(self): - self.attr3: int = 0 #: attr3 - self.attr4: int #: attr4 + self.attr4: int = 0 #: attr4 + self.attr5: int #: attr5 + self.attr6 = 0 # type: int + """attr6""" diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 04768b638..2e8ff0414 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -1418,10 +1418,8 @@ def test_autodoc_typed_instance_variables(app): ' .. py:attribute:: Class.attr3', ' :module: target.typed_vars', ' :type: int', - ' :value: None', + ' :value: 0', ' ', - ' attr3', - ' ', ' ', ' .. py:attribute:: Class.attr4', ' :module: target.typed_vars', @@ -1430,6 +1428,22 @@ def test_autodoc_typed_instance_variables(app): ' ', ' attr4', ' ', + ' ', + ' .. py:attribute:: Class.attr5', + ' :module: target.typed_vars', + ' :type: int', + ' :value: None', + ' ', + ' attr5', + ' ', + ' ', + ' .. py:attribute:: Class.attr6', + ' :module: target.typed_vars', + ' :type: int', + ' :value: None', + ' ', + ' attr6', + ' ', '', '.. py:data:: attr1', ' :module: target.typed_vars', @@ -1442,9 +1456,17 @@ def test_autodoc_typed_instance_variables(app): '.. py:data:: attr2', ' :module: target.typed_vars', ' :type: str', - " :value: None", + ' :value: None', '', ' attr2', + ' ', + '', + '.. py:data:: attr3', + ' :module: target.typed_vars', + ' :type: str', + " :value: ''", + '', + ' attr3', ' ' ] diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py index 6cc18bcb6..0bf505a33 100644 --- a/tests/test_pycode_parser.py +++ b/tests/test_pycode_parser.py @@ -99,15 +99,19 @@ def test_annotated_assignment_py36(): source = ('a: str = "Sphinx" #: comment\n' 'b: int = 1\n' '"""string on next line"""\n' - 'c: int #: comment') + 'c: int #: comment\n' + 'd = 1 # type: int\n' + '"""string on next line"""\n') parser = Parser(source) parser.parse() assert parser.comments == {('', 'a'): 'comment', ('', 'b'): 'string on next line', - ('', 'c'): 'comment'} + ('', 'c'): 'comment', + ('', 'd'): 'string on next line'} assert parser.annotations == {('', 'a'): 'str', ('', 'b'): 'int', - ('', 'c'): 'int'} + ('', 'c'): 'int', + ('', 'd'): 'int'} assert parser.definitions == {}