diff options
Diffstat (limited to 'sphinx/pycode')
-rw-r--r-- | sphinx/pycode/__init__.py | 11 | ||||
-rw-r--r-- | sphinx/pycode/ast.py | 31 | ||||
-rw-r--r-- | sphinx/pycode/parser.py | 11 |
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: |