summaryrefslogtreecommitdiff
path: root/sphinx/pycode
diff options
context:
space:
mode:
authorAdam Turner <9087854+AA-Turner@users.noreply.github.com>2022-04-18 17:33:56 +0100
committerAdam Turner <9087854+AA-Turner@users.noreply.github.com>2022-09-27 18:31:47 +0100
commit4660b62de0e83f42b6e2ede7a1a19e861e4d34e4 (patch)
tree9d20745efef0eefb29b923ccd4d2b3d48c2d9254 /sphinx/pycode
parent7649eb1505dada483af9897459f699a2a106bed4 (diff)
downloadsphinx-git-4660b62de0e83f42b6e2ede7a1a19e861e4d34e4.tar.gz
Drop Python 3.7
Diffstat (limited to 'sphinx/pycode')
-rw-r--r--sphinx/pycode/ast.py64
-rw-r--r--sphinx/pycode/parser.py23
2 files changed, 24 insertions, 63 deletions
diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py
index c0d6fc463..e61b01d18 100644
--- a/sphinx/pycode/ast.py
+++ b/sphinx/pycode/ast.py
@@ -1,18 +1,8 @@
"""Helpers for AST (Abstract Syntax Tree)."""
-import sys
+import ast
from typing import Dict, List, Optional, Type, overload
-if sys.version_info[:2] >= (3, 8):
- import ast
-else:
- try:
- # use typed_ast module if installed
- from typed_ast import ast3 as ast
- except ImportError:
- import ast # type: ignore
-
-
OPERATORS: Dict[Type[ast.AST], str] = {
ast.Add: "+",
ast.And: "and",
@@ -37,21 +27,13 @@ OPERATORS: Dict[Type[ast.AST], str] = {
def parse(code: str, mode: str = 'exec') -> "ast.AST":
- """Parse the *code* using the built-in ast or typed_ast libraries.
-
- This enables "type_comments" feature if possible.
- """
+ """Parse the *code* using the built-in ast module."""
try:
- # type_comments parameter is available on py38+
- return ast.parse(code, mode=mode, type_comments=True) # type: ignore
+ return ast.parse(code, mode=mode, type_comments=True)
except SyntaxError:
# Some syntax error found. To ignore invalid type comments, retry parsing without
# type_comments parameter (refs: https://github.com/sphinx-doc/sphinx/issues/8652).
return ast.parse(code, mode=mode)
- except TypeError:
- # fallback to ast module.
- # typed_ast is used to parse type_comments if installed.
- return ast.parse(code, mode=mode)
@overload
@@ -102,10 +84,8 @@ class _UnparseVisitor(ast.NodeVisitor):
def visit_arguments(self, node: ast.arguments) -> str:
defaults: List[Optional[ast.expr]] = list(node.defaults)
positionals = len(node.args)
- posonlyargs = 0
- if hasattr(node, "posonlyargs"): # for py38+
- posonlyargs += len(node.posonlyargs) # type:ignore
- positionals += posonlyargs
+ posonlyargs = len(node.posonlyargs)
+ positionals += posonlyargs
for _ in range(len(defaults), positionals):
defaults.insert(0, None)
@@ -114,12 +94,11 @@ class _UnparseVisitor(ast.NodeVisitor):
kw_defaults.insert(0, None)
args: List[str] = []
- if hasattr(node, "posonlyargs"): # for py38+
- for i, arg in enumerate(node.posonlyargs): # type: ignore
- args.append(self._visit_arg_with_default(arg, defaults[i]))
+ for i, arg in enumerate(node.posonlyargs):
+ args.append(self._visit_arg_with_default(arg, defaults[i]))
- if node.posonlyargs: # type: ignore
- args.append('/')
+ if node.posonlyargs:
+ args.append('/')
for i, arg in enumerate(node.args):
args.append(self._visit_arg_with_default(arg, defaults[i + posonlyargs]))
@@ -155,19 +134,19 @@ class _UnparseVisitor(ast.NodeVisitor):
["%s=%s" % (k.arg, self.visit(k.value)) for k in node.keywords])
return "%s(%s)" % (self.visit(node.func), ", ".join(args))
- def visit_Constant(self, node: ast.Constant) -> str: # type: ignore
+ def visit_Constant(self, node: ast.Constant) -> str:
if node.value is Ellipsis:
return "..."
elif isinstance(node.value, (int, float, complex)):
- if self.code and sys.version_info[:2] >= (3, 8):
- return ast.get_source_segment(self.code, node) # type: ignore
+ if self.code:
+ return ast.get_source_segment(self.code, node) or repr(node.value)
else:
return repr(node.value)
else:
return repr(node.value)
def visit_Dict(self, node: ast.Dict) -> str:
- keys = (self.visit(k) for k in node.keys)
+ keys = (self.visit(k) for k in node.keys if k is not None)
values = (self.visit(v) for v in node.values)
items = (k + ": " + v for k, v in zip(keys, values))
return "{" + ", ".join(items) + "}"
@@ -219,22 +198,5 @@ class _UnparseVisitor(ast.NodeVisitor):
else:
return "(" + ", ".join(self.visit(e) for e in node.elts) + ")"
- if sys.version_info[:2] <= (3, 7):
- # these ast nodes were deprecated in python 3.8
- def visit_Bytes(self, node: ast.Bytes) -> str:
- return repr(node.s)
-
- def visit_Ellipsis(self, node: ast.Ellipsis) -> str:
- return "..."
-
- def visit_NameConstant(self, node: ast.NameConstant) -> str:
- return repr(node.value)
-
- def visit_Num(self, node: ast.Num) -> str:
- return repr(node.n)
-
- def visit_Str(self, node: ast.Str) -> str:
- return repr(node.s)
-
def generic_visit(self, node):
raise NotImplementedError('Unable to parse %s object' % type(node).__name__)
diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py
index 1019400a8..133748cb8 100644
--- a/sphinx/pycode/parser.py
+++ b/sphinx/pycode/parser.py
@@ -1,4 +1,6 @@
"""Utilities parsing and analyzing Python code."""
+
+import ast
import inspect
import itertools
import re
@@ -9,8 +11,8 @@ from token import DEDENT, INDENT, NAME, NEWLINE, NUMBER, OP, STRING
from tokenize import COMMENT, NL
from typing import Any, Dict, List, Optional, Tuple
-from sphinx.pycode.ast import ast # for py37 or older
-from sphinx.pycode.ast import parse, unparse
+from sphinx.pycode.ast import parse as ast_parse
+from sphinx.pycode.ast import unparse as ast_unparse
comment_re = re.compile('^\\s*#: ?(.*)\r?\n?$')
indent_re = re.compile('^\\s*$')
@@ -266,7 +268,7 @@ class VariableCommentPicker(ast.NodeVisitor):
qualname = self.get_qualname_for(name)
if qualname:
basename = ".".join(qualname[:-1])
- self.annotations[(basename, name)] = unparse(annotation)
+ self.annotations[(basename, name)] = ast_unparse(annotation)
def is_final(self, decorators: List[ast.expr]) -> bool:
final = []
@@ -277,7 +279,7 @@ class VariableCommentPicker(ast.NodeVisitor):
for decorator in decorators:
try:
- if unparse(decorator) in final:
+ if ast_unparse(decorator) in final:
return True
except NotImplementedError:
pass
@@ -293,7 +295,7 @@ class VariableCommentPicker(ast.NodeVisitor):
for decorator in decorators:
try:
- if unparse(decorator) in overload:
+ if ast_unparse(decorator) in overload:
return True
except NotImplementedError:
pass
@@ -304,12 +306,9 @@ class VariableCommentPicker(ast.NodeVisitor):
"""Returns the name of the first argument if in a function."""
if self.current_function and self.current_function.args.args:
return self.current_function.args.args[0]
- elif (self.current_function and
- getattr(self.current_function.args, 'posonlyargs', None)):
- # for py38+
- return self.current_function.args.posonlyargs[0] # type: ignore
- else:
- return None
+ if self.current_function and self.current_function.args.posonlyargs:
+ return self.current_function.args.posonlyargs[0]
+ return None
def get_line(self, lineno: int) -> str:
"""Returns specified line."""
@@ -553,7 +552,7 @@ class Parser:
def parse_comments(self) -> None:
"""Parse the code and pick up comments."""
- tree = parse(self.code)
+ tree = ast_parse(self.code)
picker = VariableCommentPicker(self.code.splitlines(True), self.encoding)
picker.visit(tree)
self.annotations = picker.annotations