summaryrefslogtreecommitdiff
path: root/sphinx/pycode
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2020-02-09 00:57:53 +0900
committerTakeshi KOMIYA <i.tkomiya@gmail.com>2020-02-09 00:57:53 +0900
commit2e87ee85a22279ee4ecc658f830520a88c90236d (patch)
tree124b080e0203aead764362ba1e5bd11da62822e5 /sphinx/pycode
parentd4aeae475943aef9b935f7487baf90ccc1c58b42 (diff)
parent1e5342faa9147c7a3c60e41dc7671e88f6795855 (diff)
downloadsphinx-git-2e87ee85a22279ee4ecc658f830520a88c90236d.tar.gz
Merge branch '2.0'
Diffstat (limited to 'sphinx/pycode')
-rw-r--r--sphinx/pycode/__init__.py8
-rw-r--r--sphinx/pycode/ast.py2
-rw-r--r--sphinx/pycode/parser.py29
3 files changed, 34 insertions, 5 deletions
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 12bd8d9ef..55d5d2c1d 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -142,9 +142,10 @@ class ModuleAnalyzer:
self.code = source.read()
# will be filled by parse()
- self.attr_docs = None # type: Dict[Tuple[str, str], List[str]]
- self.tagorder = None # type: Dict[str, int]
- self.tags = None # type: Dict[str, Tuple[str, int, int]]
+ self.annotations = None # type: Dict[Tuple[str, str], str]
+ self.attr_docs = None # type: Dict[Tuple[str, str], List[str]]
+ self.tagorder = None # type: Dict[str, int]
+ self.tags = None # type: Dict[str, Tuple[str, int, int]]
def parse(self) -> None:
"""Parse the source code."""
@@ -159,6 +160,7 @@ class ModuleAnalyzer:
else:
self.attr_docs[scope] = ['']
+ self.annotations = parser.annotations
self.tags = parser.definitions
self.tagorder = parser.deforders
except Exception as exc:
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 c14d5773b..cb3cf0cc1 100644
--- a/sphinx/pycode/parser.py
+++ b/sphinx/pycode/parser.py
@@ -7,7 +7,6 @@
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
-import ast
import inspect
import itertools
import re
@@ -17,6 +16,9 @@ from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING
from tokenize import COMMENT, NL
from typing import Any, Dict, List, Tuple
+from sphinx.pycode.ast import ast # for py37 or older
+from sphinx.pycode.ast import parse, unparse
+
comment_re = re.compile('^\\s*#: ?(.*)\r?\n?$')
indent_re = re.compile('^\\s*$')
@@ -226,6 +228,7 @@ class VariableCommentPicker(ast.NodeVisitor):
self.current_classes = [] # type: List[str]
self.current_function = None # type: ast.FunctionDef
self.comments = {} # type: Dict[Tuple[str, str], str]
+ self.annotations = {} # type: Dict[Tuple[str, str], str]
self.previous = None # type: ast.AST
self.deforders = {} # type: Dict[str, int]
super().__init__()
@@ -254,6 +257,18 @@ class VariableCommentPicker(ast.NodeVisitor):
self.comments[(context, name)] = comment
+ def add_variable_annotation(self, name: str, annotation: ast.AST) -> None:
+ if self.current_function:
+ if self.current_classes and self.context[-1] == "__init__":
+ # store variable comments inside __init__ method of classes
+ context = ".".join(self.context[:-1])
+ else:
+ return
+ else:
+ context = ".".join(self.context)
+
+ self.annotations[(context, name)] = unparse(annotation)
+
def get_self(self) -> ast.arg:
"""Returns the name of first argument if in function."""
if self.current_function and self.current_function.args.args:
@@ -295,6 +310,14 @@ class VariableCommentPicker(ast.NodeVisitor):
except TypeError:
return # this assignment is not new definition!
+ # record annotation
+ if hasattr(node, 'annotation') and node.annotation: # type: ignore
+ for varname in varnames:
+ 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:]] +
self.buffers[node.lineno:])
@@ -468,6 +491,7 @@ class Parser:
def __init__(self, code: str, encoding: str = 'utf-8') -> None:
self.code = filter_whitespace(code)
self.encoding = encoding
+ self.annotations = {} # type: Dict[Tuple[str, str], str]
self.comments = {} # type: Dict[Tuple[str, str], str]
self.deforders = {} # type: Dict[str, int]
self.definitions = {} # type: Dict[str, Tuple[str, int, int]]
@@ -479,9 +503,10 @@ class Parser:
def parse_comments(self) -> None:
"""Parse the code and pick up comments."""
- tree = ast.parse(self.code)
+ tree = parse(self.code)
picker = VariableCommentPicker(self.code.splitlines(True), self.encoding)
picker.visit(tree)
+ self.annotations = picker.annotations
self.comments = picker.comments
self.deforders = picker.deforders