summaryrefslogtreecommitdiffstats
path: root/sphinx/pycode
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/pycode')
-rw-r--r--sphinx/pycode/__init__.py11
-rw-r--r--sphinx/pycode/ast.py31
-rw-r--r--sphinx/pycode/parser.py11
3 files changed, 35 insertions, 18 deletions
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 55835ec..92de047 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -69,12 +69,13 @@ class ModuleAnalyzer:
return filename, None
@classmethod
- def for_string(cls, string: str, modname: str, srcname: str = '<string>',
- ) -> ModuleAnalyzer:
+ def for_string(
+ cls: type[ModuleAnalyzer], string: str, modname: str, srcname: str = '<string>',
+ ) -> ModuleAnalyzer:
return cls(string, modname, srcname)
@classmethod
- def for_file(cls, filename: str, modname: str) -> ModuleAnalyzer:
+ def for_file(cls: type[ModuleAnalyzer], filename: str, modname: str) -> ModuleAnalyzer:
if ('file', filename) in cls.cache:
return cls.cache['file', filename]
try:
@@ -87,7 +88,7 @@ class ModuleAnalyzer:
return obj
@classmethod
- def for_module(cls, modname: str) -> ModuleAnalyzer:
+ def for_module(cls: type[ModuleAnalyzer], modname: str) -> ModuleAnalyzer:
if ('module', modname) in cls.cache:
entry = cls.cache['module', modname]
if isinstance(entry, PycodeError):
@@ -127,7 +128,7 @@ class ModuleAnalyzer:
self.attr_docs = {}
for (scope, comment) in parser.comments.items():
if comment:
- self.attr_docs[scope] = comment.splitlines() + ['']
+ self.attr_docs[scope] = [*comment.splitlines(), '']
else:
self.attr_docs[scope] = ['']
diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py
index e5914cc..7517d48 100644
--- a/sphinx/pycode/ast.py
+++ b/sphinx/pycode/ast.py
@@ -3,7 +3,7 @@
from __future__ import annotations
import ast
-from typing import overload
+from typing import NoReturn, overload
OPERATORS: dict[type[ast.AST], str] = {
ast.Add: "+",
@@ -85,9 +85,8 @@ class _UnparseVisitor(ast.NodeVisitor):
for _ in range(len(kw_defaults), len(node.kwonlyargs)):
kw_defaults.insert(0, None)
- args: list[str] = []
- for i, arg in enumerate(node.posonlyargs):
- args.append(self._visit_arg_with_default(arg, defaults[i]))
+ args: list[str] = [self._visit_arg_with_default(arg, defaults[i])
+ for i, arg in enumerate(node.posonlyargs)]
if node.posonlyargs:
args.append('/')
@@ -115,15 +114,17 @@ class _UnparseVisitor(ast.NodeVisitor):
# Special case ``**`` to not have surrounding spaces.
if isinstance(node.op, ast.Pow):
return "".join(map(self.visit, (node.left, node.op, node.right)))
- return " ".join(self.visit(e) for e in [node.left, node.op, node.right])
+ return " ".join(map(self.visit, (node.left, node.op, node.right)))
def visit_BoolOp(self, node: ast.BoolOp) -> str:
op = " %s " % self.visit(node.op)
return op.join(self.visit(e) for e in node.values)
def visit_Call(self, node: ast.Call) -> str:
- args = ', '.join([self.visit(e) for e in node.args]
- + [f"{k.arg}={self.visit(k.value)}" for k in node.keywords])
+ args = ', '.join(
+ [self.visit(e) for e in node.args]
+ + [f"{k.arg}={self.visit(k.value)}" for k in node.keywords],
+ )
return f"{self.visit(node.func)}({args})"
def visit_Constant(self, node: ast.Constant) -> str:
@@ -155,6 +156,20 @@ class _UnparseVisitor(ast.NodeVisitor):
def visit_Set(self, node: ast.Set) -> str:
return "{" + ", ".join(self.visit(e) for e in node.elts) + "}"
+ def visit_Slice(self, node: ast.Slice) -> str:
+ if not node.lower and not node.upper and not node.step:
+ # Empty slice with default values -> [:]
+ return ":"
+
+ start = self.visit(node.lower) if node.lower else ""
+ stop = self.visit(node.upper) if node.upper else ""
+ if not node.step:
+ # Default step size -> [start:stop]
+ return f"{start}:{stop}"
+
+ step = self.visit(node.step) if node.step else ""
+ return f"{start}:{stop}:{step}"
+
def visit_Subscript(self, node: ast.Subscript) -> str:
def is_simple_tuple(value: ast.expr) -> bool:
return (
@@ -184,5 +199,5 @@ class _UnparseVisitor(ast.NodeVisitor):
else:
return "(" + ", ".join(self.visit(e) for e in node.elts) + ")"
- def generic_visit(self, node):
+ def generic_visit(self, node: ast.AST) -> NoReturn:
raise NotImplementedError('Unable to parse %s object' % type(node).__name__)
diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py
index a0f855d..2bfe25b 100644
--- a/sphinx/pycode/parser.py
+++ b/sphinx/pycode/parser.py
@@ -4,8 +4,10 @@ from __future__ import annotations
import ast
import contextlib
+import functools
import inspect
import itertools
+import operator
import re
import tokenize
from inspect import Signature
@@ -243,7 +245,7 @@ class VariableCommentPicker(ast.NodeVisitor):
else:
return None
else:
- return self.context + [name]
+ return [*self.context, name]
def add_entry(self, name: str) -> None:
qualname = self.get_qualname_for(name)
@@ -350,9 +352,8 @@ class VariableCommentPicker(ast.NodeVisitor):
"""Handles Assign node and pick up a variable comment."""
try:
targets = get_assign_targets(node)
- varnames: list[str] = sum(
- [get_lvar_names(t, self=self.get_self()) for t in targets], [],
- )
+ varnames: list[str] = functools.reduce(
+ operator.iadd, [get_lvar_names(t, self=self.get_self()) for t in targets], [])
current_line = self.get_line(node.lineno)
except TypeError:
return # this assignment is not new definition!
@@ -476,7 +477,7 @@ class DefinitionFinder(TokenProcessor):
def add_definition(self, name: str, entry: tuple[str, int, int]) -> None:
"""Add a location of definition."""
- if self.indents and self.indents[-1][0] == 'def' and entry[0] == 'def':
+ if self.indents and self.indents[-1][0] == entry[0] == 'def':
# ignore definition of inner function
pass
else: