summaryrefslogtreecommitdiffstats
path: root/sphinx/ext/napoleon
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/ext/napoleon')
-rw-r--r--sphinx/ext/napoleon/__init__.py19
-rw-r--r--sphinx/ext/napoleon/docstring.py66
2 files changed, 46 insertions, 39 deletions
diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py
index 61aa3d8..581f3ea 100644
--- a/sphinx/ext/napoleon/__init__.py
+++ b/sphinx/ext/napoleon/__init__.py
@@ -2,13 +2,17 @@
from __future__ import annotations
-from typing import Any
+from typing import TYPE_CHECKING, Any
import sphinx
from sphinx.application import Sphinx
from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
from sphinx.util import inspect
+if TYPE_CHECKING:
+ from sphinx.config import _ConfigRebuild
+ from sphinx.util.typing import ExtensionMetadata
+
class Config:
"""Sphinx napoleon extension settings in `conf.py`.
@@ -261,8 +265,9 @@ class Config:
Use the type annotations of class attributes that are documented in the docstring
but do not have a type in the docstring.
- """
- _config_values = {
+ """ # NoQA: D301
+
+ _config_values: dict[str, tuple[Any, _ConfigRebuild]] = {
'napoleon_google_docstring': (True, 'env'),
'napoleon_numpy_docstring': (True, 'env'),
'napoleon_include_init_with_doc': (False, 'env'),
@@ -288,7 +293,7 @@ class Config:
setattr(self, name, value)
-def setup(app: Sphinx) -> dict[str, Any]:
+def setup(app: Sphinx) -> ExtensionMetadata:
"""Sphinx extension setup function.
When the extension is loaded, Sphinx imports this module and executes
@@ -326,7 +331,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
def _patch_python_domain() -> None:
- from sphinx.domains.python import PyObject, PyTypedField
+ from sphinx.domains.python._object import PyObject, PyTypedField
from sphinx.locale import _
for doc_field in PyObject.doc_field_types:
if doc_field.name == 'parameter':
@@ -335,7 +340,7 @@ def _patch_python_domain() -> None:
PyObject.doc_field_types.append(
PyTypedField('keyword', label=_('Keyword Arguments'),
names=('keyword', 'kwarg', 'kwparam'),
- typerolename='obj', typenames=('paramtype', 'kwtype'),
+ typerolename='class', typenames=('paramtype', 'kwtype'),
can_collapse=True))
@@ -386,7 +391,7 @@ def _process_docstring(app: Sphinx, what: str, name: str, obj: Any,
docstring = GoogleDocstring(result_lines, app.config, app, what, name,
obj, options)
result_lines = docstring.lines()
- lines[:] = result_lines[:]
+ lines[:] = result_lines.copy()
def _skip_member(app: Sphinx, what: str, name: str, obj: Any,
diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py
index 2ffde39..2ce3b2d 100644
--- a/sphinx/ext/napoleon/docstring.py
+++ b/sphinx/ext/napoleon/docstring.py
@@ -7,6 +7,7 @@ import contextlib
import inspect
import re
from functools import partial
+from itertools import starmap
from typing import TYPE_CHECKING, Any, Callable
from sphinx.locale import _, __
@@ -14,6 +15,8 @@ from sphinx.util import logging
from sphinx.util.typing import get_type_hints, stringify_annotation
if TYPE_CHECKING:
+ from collections.abc import Iterator
+
from sphinx.application import Sphinx
from sphinx.config import Config as SphinxConfig
@@ -145,7 +148,7 @@ class GoogleDocstring:
"""
_name_rgx = re.compile(r"^\s*((?::(?P<role>\S+):)?`(?P<name>~?[a-zA-Z0-9_.-]+)`|"
- r" (?P<name2>~?[a-zA-Z0-9_.-]+))\s*", re.X)
+ r" (?P<name2>~?[a-zA-Z0-9_.-]+))\s*", re.VERBOSE)
def __init__(
self,
@@ -304,19 +307,18 @@ class GoogleDocstring:
_type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {})
indent = self._get_indent(line) + 1
- _descs = [_desc] + self._dedent(self._consume_indented_block(indent))
+ _descs = [_desc, *self._dedent(self._consume_indented_block(indent))]
_descs = self.__class__(_descs, self._config).lines()
return _name, _type, _descs
def _consume_fields(self, parse_type: bool = True, prefer_type: bool = False,
multiple: bool = False) -> list[tuple[str, str, list[str]]]:
self._consume_empty()
- fields = []
+ fields: list[tuple[str, str, list[str]]] = []
while not self._is_section_break():
_name, _type, _desc = self._consume_field(parse_type, prefer_type)
if multiple and _name:
- for name in _name.split(","):
- fields.append((name.strip(), _type, _desc))
+ fields.extend((name.strip(), _type, _desc) for name in _name.split(","))
elif _name or _type or _desc:
fields.append((_name, _type, _desc))
return fields
@@ -327,7 +329,7 @@ class GoogleDocstring:
if not colon or not _desc:
_type, _desc = _desc, _type
_desc += colon
- _descs = [_desc] + self._dedent(self._consume_to_end())
+ _descs = [_desc, *self._dedent(self._consume_to_end())]
_descs = self.__class__(_descs, self._config).lines()
return _type, _descs
@@ -399,15 +401,15 @@ class GoogleDocstring:
def _fix_field_desc(self, desc: list[str]) -> list[str]:
if self._is_list(desc):
- desc = [''] + desc
+ desc = ['', *desc]
elif desc[0].endswith('::'):
desc_block = desc[1:]
indent = self._get_indent(desc[0])
block_indent = self._get_initial_indent(desc_block)
if block_indent > indent:
- desc = [''] + desc
+ desc = ['', *desc]
else:
- desc = ['', desc[0]] + self._indent(desc_block, 4)
+ desc = ['', desc[0], *self._indent(desc_block, 4)]
return desc
def _format_admonition(self, admonition: str, lines: list[str]) -> list[str]:
@@ -416,7 +418,7 @@ class GoogleDocstring:
return [f'.. {admonition}:: {lines[0].strip()}', '']
elif lines:
lines = self._indent(self._dedent(lines), 3)
- return ['.. %s::' % admonition, ''] + lines + ['']
+ return ['.. %s::' % admonition, '', *lines, '']
else:
return ['.. %s::' % admonition, '']
@@ -453,7 +455,7 @@ class GoogleDocstring:
if _type:
lines.append(f':{type_role} {_name}: {_type}')
- return lines + ['']
+ return [*lines, '']
def _format_field(self, _name: str, _type: str, _desc: list[str]) -> list[str]:
_desc = self._strip_empty(_desc)
@@ -480,7 +482,7 @@ class GoogleDocstring:
if _desc[0]:
return [field + _desc[0]] + _desc[1:]
else:
- return [field] + _desc
+ return [field, *_desc]
else:
return [field]
@@ -537,7 +539,7 @@ class GoogleDocstring:
return [(' ' * n) + line for line in lines]
def _is_indented(self, line: str, indent: int = 1) -> bool:
- for i, s in enumerate(line): # noqa: SIM110
+ for i, s in enumerate(line): # NoQA: SIM110
if i >= indent:
return True
elif not s.isspace():
@@ -623,7 +625,7 @@ class GoogleDocstring:
self._is_in_section = True
self._section_indent = self._get_current_indent()
if _directive_regex.match(section):
- lines = [section] + self._consume_to_next_section()
+ lines = [section, *self._consume_to_next_section()]
else:
lines = self._sections[section.lower()](section)
finally:
@@ -711,7 +713,7 @@ class GoogleDocstring:
else:
header = '.. rubric:: %s' % section
if lines:
- return [header, ''] + lines + ['']
+ return [header, '', *lines, '']
else:
return [header, '']
@@ -733,7 +735,7 @@ class GoogleDocstring:
if 'no-index' in self._opt or 'noindex' in self._opt:
lines.append(' :no-index:')
if _desc:
- lines.extend([''] + self._indent(_desc, 3))
+ lines.extend(['', *self._indent(_desc, 3)])
lines.append('')
return lines
@@ -888,7 +890,7 @@ def _recombine_set_tokens(tokens: list[str]) -> list[str]:
token_queue = collections.deque(tokens)
keywords = ("optional", "default")
- def takewhile_set(tokens):
+ def takewhile_set(tokens: collections.deque[str]) -> Iterator[str]:
open_braces = 0
previous_token = None
while True:
@@ -924,7 +926,7 @@ def _recombine_set_tokens(tokens: list[str]) -> list[str]:
if open_braces == 0:
break
- def combine_set(tokens):
+ def combine_set(tokens: collections.deque[str]) -> Iterator[str]:
while True:
try:
token = tokens.popleft()
@@ -941,7 +943,7 @@ def _recombine_set_tokens(tokens: list[str]) -> list[str]:
def _tokenize_type_spec(spec: str) -> list[str]:
- def postprocess(item):
+ def postprocess(item: str) -> list[str]:
if _default_regex.match(item):
default = item[:7]
# can't be separated by anything other than a single space
@@ -962,7 +964,7 @@ def _tokenize_type_spec(spec: str) -> list[str]:
def _token_type(token: str, location: str | None = None) -> str:
- def is_numeric(token):
+ def is_numeric(token: str) -> bool:
try:
# use complex to make sure every numeric value is detected as literal
complex(token)
@@ -1026,7 +1028,7 @@ def _convert_numpy_type_spec(
if translations is None:
translations = {}
- def convert_obj(obj, translations, default_translation):
+ def convert_obj(obj: str, translations: dict[str, str], default_translation: str) -> str:
translation = translations.get(obj, obj)
# use :class: (the default) only if obj is not a standard singleton
@@ -1155,6 +1157,7 @@ class NumpyDocstring(GoogleDocstring):
The lines of the docstring in a list.
"""
+
def __init__(
self,
docstring: str | list[str],
@@ -1180,13 +1183,13 @@ class NumpyDocstring(GoogleDocstring):
elif filepath is None:
filepath = ""
- return ":".join([filepath, "docstring of %s" % name])
+ return f"{filepath}:docstring of {name}"
def _escape_args_and_kwargs(self, name: str) -> str:
func = super()._escape_args_and_kwargs
if ", " in name:
- return ", ".join(func(param) for param in name.split(", "))
+ return ", ".join(map(func, name.split(", ")))
else:
return func(name)
@@ -1233,7 +1236,7 @@ class NumpyDocstring(GoogleDocstring):
line1, line2 = self._lines.get(0), self._lines.get(1)
return (not self._lines or
self._is_section_header() or
- ['', ''] == [line1, line2] or
+ (line1 == line2 == '') or
(self._is_in_section and
line1 and
not self._is_indented(line1, self._section_indent)))
@@ -1269,7 +1272,7 @@ class NumpyDocstring(GoogleDocstring):
func_name1, func_name2, :meth:`func_name`, func_name3
"""
- items = []
+ items: list[tuple[str, list[str], str | None]] = []
def parse_item_name(text: str) -> tuple[str, str | None]:
"""Match ':role:`name`' or 'name'"""
@@ -1286,10 +1289,12 @@ class NumpyDocstring(GoogleDocstring):
if not name:
return
name, role = parse_item_name(name)
- items.append((name, list(rest), role))
- del rest[:]
+ items.append((name, rest.copy(), role))
+ rest.clear()
- def translate(func, description, role):
+ def translate(
+ func: str, description: list[str], role: str | None,
+ ) -> tuple[str, list[str], str | None]:
translations = self._config.napoleon_type_aliases
if role is not None or not translations:
return func, description, role
@@ -1336,10 +1341,7 @@ class NumpyDocstring(GoogleDocstring):
return []
# apply type aliases
- items = [
- translate(func, description, role)
- for func, description, role in items
- ]
+ items = list(starmap(translate, items))
lines: list[str] = []
last_had_desc = True