mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Enable automatic formatting for `sphinx/ext/napoleon/
` (#12972)
This commit is contained in:
parent
a6e449094a
commit
f6590c5a33
@ -470,8 +470,6 @@ exclude = [
|
||||
"sphinx/ext/inheritance_diagram.py",
|
||||
"sphinx/ext/linkcode.py",
|
||||
"sphinx/ext/mathjax.py",
|
||||
"sphinx/ext/napoleon/__init__.py",
|
||||
"sphinx/ext/napoleon/docstring.py",
|
||||
"sphinx/ext/todo.py",
|
||||
"sphinx/ext/viewcode.py",
|
||||
"sphinx/registry.py",
|
||||
|
@ -333,19 +333,26 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
def _patch_python_domain() -> None:
|
||||
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':
|
||||
doc_field.names = ('param', 'parameter', 'arg', 'argument')
|
||||
break
|
||||
PyObject.doc_field_types.append(
|
||||
PyTypedField('keyword', label=_('Keyword Arguments'),
|
||||
names=('keyword', 'kwarg', 'kwparam'),
|
||||
typerolename='class', typenames=('paramtype', 'kwtype'),
|
||||
can_collapse=True))
|
||||
PyTypedField(
|
||||
'keyword',
|
||||
label=_('Keyword Arguments'),
|
||||
names=('keyword', 'kwarg', 'kwparam'),
|
||||
typerolename='class',
|
||||
typenames=('paramtype', 'kwtype'),
|
||||
can_collapse=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _process_docstring(app: Sphinx, what: str, name: str, obj: Any,
|
||||
options: Any, lines: list[str]) -> None:
|
||||
def _process_docstring(
|
||||
app: Sphinx, what: str, name: str, obj: Any, options: Any, lines: list[str]
|
||||
) -> None:
|
||||
"""Process the docstring for a given python object.
|
||||
|
||||
Called when autodoc has read and processed a docstring. `lines` is a list
|
||||
@ -384,18 +391,21 @@ def _process_docstring(app: Sphinx, what: str, name: str, obj: Any,
|
||||
result_lines = lines
|
||||
docstring: GoogleDocstring
|
||||
if app.config.napoleon_numpy_docstring:
|
||||
docstring = NumpyDocstring(result_lines, app.config, app, what, name,
|
||||
obj, options)
|
||||
docstring = NumpyDocstring(
|
||||
result_lines, app.config, app, what, name, obj, options
|
||||
)
|
||||
result_lines = docstring.lines()
|
||||
if app.config.napoleon_google_docstring:
|
||||
docstring = GoogleDocstring(result_lines, app.config, app, what, name,
|
||||
obj, options)
|
||||
docstring = GoogleDocstring(
|
||||
result_lines, app.config, app, what, name, obj, options
|
||||
)
|
||||
result_lines = docstring.lines()
|
||||
lines[:] = result_lines.copy()
|
||||
|
||||
|
||||
def _skip_member(app: Sphinx, what: str, name: str, obj: Any,
|
||||
skip: bool, options: Any) -> bool | None:
|
||||
def _skip_member(
|
||||
app: Sphinx, what: str, name: str, obj: Any, skip: bool, options: Any
|
||||
) -> bool | None:
|
||||
"""Determine if private and special class members are included in docs.
|
||||
|
||||
The following settings in conf.py determine if private and special class
|
||||
@ -458,22 +468,25 @@ def _skip_member(app: Sphinx, what: str, name: str, obj: Any,
|
||||
except Exception:
|
||||
cls_is_owner = False
|
||||
else:
|
||||
cls_is_owner = (cls and hasattr(cls, name) and # type: ignore[assignment]
|
||||
name in cls.__dict__)
|
||||
cls_is_owner = (
|
||||
cls # type: ignore[assignment]
|
||||
and hasattr(cls, name)
|
||||
and name in cls.__dict__
|
||||
)
|
||||
else:
|
||||
cls_is_owner = False
|
||||
|
||||
if what == 'module' or cls_is_owner:
|
||||
is_init = (name == '__init__')
|
||||
is_special = (not is_init and name.startswith('__') and
|
||||
name.endswith('__'))
|
||||
is_private = (not is_init and not is_special and
|
||||
name.startswith('_'))
|
||||
is_init = name == '__init__'
|
||||
is_special = not is_init and name.startswith('__') and name.endswith('__')
|
||||
is_private = not is_init and not is_special and name.startswith('_')
|
||||
inc_init = app.config.napoleon_include_init_with_doc
|
||||
inc_special = app.config.napoleon_include_special_with_doc
|
||||
inc_private = app.config.napoleon_include_private_with_doc
|
||||
if ((is_special and inc_special) or
|
||||
(is_private and inc_private) or
|
||||
(is_init and inc_init)):
|
||||
if (
|
||||
(is_special and inc_special)
|
||||
or (is_private and inc_private)
|
||||
or (is_init and inc_init)
|
||||
):
|
||||
return False
|
||||
return None
|
||||
|
@ -31,7 +31,8 @@ _xref_or_code_regex = re.compile(
|
||||
r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|'
|
||||
r'(?:``.+?``)|'
|
||||
r'(?::meta .+:.*)|'
|
||||
r'(?:`.+?\s*(?<!\x00)<.*?>`))')
|
||||
r'(?:`.+?\s*(?<!\x00)<.*?>`))'
|
||||
)
|
||||
_xref_regex = re.compile(
|
||||
r'(?:(?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:)?`.+?`)',
|
||||
)
|
||||
@ -39,17 +40,18 @@ _bullet_list_regex = re.compile(r'^(\*|\+|\-)(\s+\S|\s*$)')
|
||||
_enumerated_list_regex = re.compile(
|
||||
r'^(?P<paren>\()?'
|
||||
r'(\d+|#|[ivxlcdm]+|[IVXLCDM]+|[a-zA-Z])'
|
||||
r'(?(paren)\)|\.)(\s+\S|\s*$)')
|
||||
r'(?(paren)\)|\.)(\s+\S|\s*$)'
|
||||
)
|
||||
_token_regex = re.compile(
|
||||
r"(,\sor\s|\sor\s|\sof\s|:\s|\sto\s|,\sand\s|\sand\s|,\s"
|
||||
r"|[{]|[}]"
|
||||
r'(,\sor\s|\sor\s|\sof\s|:\s|\sto\s|,\sand\s|\sand\s|,\s'
|
||||
r'|[{]|[}]'
|
||||
r'|"(?:\\"|[^"])*"'
|
||||
r"|'(?:\\'|[^'])*')",
|
||||
)
|
||||
_default_regex = re.compile(
|
||||
r"^default[^_0-9A-Za-z].*$",
|
||||
r'^default[^_0-9A-Za-z].*$',
|
||||
)
|
||||
_SINGLETONS = ("None", "True", "False", "Ellipsis")
|
||||
_SINGLETONS = ('None', 'True', 'False', 'Ellipsis')
|
||||
|
||||
|
||||
class Deque(collections.deque[Any]):
|
||||
@ -147,8 +149,11 @@ 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.VERBOSE)
|
||||
_name_rgx = re.compile(
|
||||
r'^\s*((?::(?P<role>\S+):)?`(?P<name>~?[a-zA-Z0-9_.-]+)`|'
|
||||
r' (?P<name2>~?[a-zA-Z0-9_.-]+))\s*',
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -261,9 +266,8 @@ class GoogleDocstring:
|
||||
def _consume_indented_block(self, indent: int = 1) -> list[str]:
|
||||
lines = []
|
||||
line = self._lines.get(0)
|
||||
while (
|
||||
not self._is_section_break() and
|
||||
(not line or self._is_indented(line, indent))
|
||||
while not self._is_section_break() and (
|
||||
not line or self._is_indented(line, indent)
|
||||
):
|
||||
lines.append(self._lines.next())
|
||||
line = self._lines.get(0)
|
||||
@ -271,9 +275,7 @@ class GoogleDocstring:
|
||||
|
||||
def _consume_contiguous(self) -> list[str]:
|
||||
lines = []
|
||||
while (self._lines and
|
||||
self._lines.get(0) and
|
||||
not self._is_section_header()):
|
||||
while self._lines and self._lines.get(0) and not self._is_section_header():
|
||||
lines.append(self._lines.next())
|
||||
return lines
|
||||
|
||||
@ -285,8 +287,11 @@ class GoogleDocstring:
|
||||
line = self._lines.get(0)
|
||||
return lines
|
||||
|
||||
def _consume_field(self, parse_type: bool = True, prefer_type: bool = False,
|
||||
) -> tuple[str, str, list[str]]:
|
||||
def _consume_field(
|
||||
self,
|
||||
parse_type: bool = True,
|
||||
prefer_type: bool = False,
|
||||
) -> tuple[str, str, list[str]]:
|
||||
line = self._lines.next()
|
||||
|
||||
before, colon, after = self._partition_field_on_colon(line)
|
||||
@ -311,14 +316,15 @@ class GoogleDocstring:
|
||||
_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]]]:
|
||||
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: 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:
|
||||
fields.extend((name.strip(), _type, _desc) for name in _name.split(","))
|
||||
fields.extend((name.strip(), _type, _desc) for name in _name.split(','))
|
||||
elif _name or _type or _desc:
|
||||
fields.append((_name, _type, _desc))
|
||||
return fields
|
||||
@ -333,8 +339,9 @@ class GoogleDocstring:
|
||||
_descs = self.__class__(_descs, self._config).lines()
|
||||
return _type, _descs
|
||||
|
||||
def _consume_returns_section(self, preprocess_types: bool = False,
|
||||
) -> list[tuple[str, str, list[str]]]:
|
||||
def _consume_returns_section(
|
||||
self, preprocess_types: bool = False
|
||||
) -> list[tuple[str, str, list[str]]]:
|
||||
lines = self._dedent(self._consume_to_next_section())
|
||||
if lines:
|
||||
before, colon, after = self._partition_field_on_colon(lines[0])
|
||||
@ -348,9 +355,10 @@ class GoogleDocstring:
|
||||
|
||||
_type = before
|
||||
|
||||
if (_type and preprocess_types and
|
||||
self._config.napoleon_preprocess_types):
|
||||
_type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {})
|
||||
if _type and preprocess_types and self._config.napoleon_preprocess_types:
|
||||
_type = _convert_type_spec(
|
||||
_type, self._config.napoleon_type_aliases or {}
|
||||
)
|
||||
|
||||
_desc = self.__class__(_desc, self._config).lines()
|
||||
return [(_name, _type, _desc)]
|
||||
@ -389,7 +397,9 @@ class GoogleDocstring:
|
||||
return [line[min_indent:] for line in lines]
|
||||
|
||||
def _escape_args_and_kwargs(self, name: str) -> str:
|
||||
if name.endswith('_') and getattr(self._config, 'strip_signature_backslash', False):
|
||||
if name.endswith('_') and getattr(
|
||||
self._config, 'strip_signature_backslash', False
|
||||
):
|
||||
name = name[:-1] + r'\_'
|
||||
|
||||
if name[:2] == '**':
|
||||
@ -423,7 +433,10 @@ class GoogleDocstring:
|
||||
return ['.. %s::' % admonition, '']
|
||||
|
||||
def _format_block(
|
||||
self, prefix: str, lines: list[str], padding: str | None = None,
|
||||
self,
|
||||
prefix: str,
|
||||
lines: list[str],
|
||||
padding: str | None = None,
|
||||
) -> list[str]:
|
||||
if lines:
|
||||
if padding is None:
|
||||
@ -440,9 +453,12 @@ class GoogleDocstring:
|
||||
else:
|
||||
return [prefix]
|
||||
|
||||
def _format_docutils_params(self, fields: list[tuple[str, str, list[str]]],
|
||||
field_role: str = 'param', type_role: str = 'type',
|
||||
) -> list[str]:
|
||||
def _format_docutils_params(
|
||||
self,
|
||||
fields: list[tuple[str, str, list[str]]],
|
||||
field_role: str = 'param',
|
||||
type_role: str = 'type',
|
||||
) -> list[str]:
|
||||
lines = []
|
||||
for _name, _type, _desc in fields:
|
||||
_desc = self._strip_empty(_desc)
|
||||
@ -486,8 +502,11 @@ class GoogleDocstring:
|
||||
else:
|
||||
return [field]
|
||||
|
||||
def _format_fields(self, field_type: str, fields: list[tuple[str, str, list[str]]],
|
||||
) -> list[str]:
|
||||
def _format_fields(
|
||||
self,
|
||||
field_type: str,
|
||||
fields: list[tuple[str, str, list[str]]],
|
||||
) -> list[str]:
|
||||
field_type = ':%s:' % field_type.strip()
|
||||
padding = ' ' * len(field_type)
|
||||
multi = len(fields) > 1
|
||||
@ -579,11 +598,15 @@ class GoogleDocstring:
|
||||
|
||||
def _is_section_break(self) -> bool:
|
||||
line = self._lines.get(0)
|
||||
return (not self._lines or
|
||||
self._is_section_header() or
|
||||
(self._is_in_section and
|
||||
line and
|
||||
not self._is_indented(line, self._section_indent)))
|
||||
return (
|
||||
not self._lines
|
||||
or self._is_section_header()
|
||||
or (
|
||||
self._is_in_section
|
||||
and line
|
||||
and not self._is_indented(line, self._section_indent)
|
||||
)
|
||||
)
|
||||
|
||||
def _load_custom_sections(self) -> None:
|
||||
if self._config.napoleon_custom_sections is not None:
|
||||
@ -594,18 +617,20 @@ class GoogleDocstring:
|
||||
self._sections[entry.lower()] = self._parse_custom_generic_section
|
||||
else:
|
||||
# otherwise, assume entry is container;
|
||||
if entry[1] == "params_style":
|
||||
self._sections[entry[0].lower()] = \
|
||||
if entry[1] == 'params_style':
|
||||
self._sections[entry[0].lower()] = (
|
||||
self._parse_custom_params_style_section
|
||||
elif entry[1] == "returns_style":
|
||||
self._sections[entry[0].lower()] = \
|
||||
)
|
||||
elif entry[1] == 'returns_style':
|
||||
self._sections[entry[0].lower()] = (
|
||||
self._parse_custom_returns_style_section
|
||||
)
|
||||
else:
|
||||
# [0] is new section, [1] is the section to alias.
|
||||
# in the case of key mismatch, just handle as generic section.
|
||||
self._sections[entry[0].lower()] = \
|
||||
self._sections.get(entry[1].lower(),
|
||||
self._parse_custom_generic_section)
|
||||
self._sections[entry[0].lower()] = self._sections.get(
|
||||
entry[1].lower(), self._parse_custom_generic_section
|
||||
)
|
||||
|
||||
def _parse(self) -> None:
|
||||
self._parsed_lines = self._consume_empty()
|
||||
@ -721,9 +746,8 @@ class GoogleDocstring:
|
||||
fields = self._consume_fields()
|
||||
if self._config.napoleon_use_keyword:
|
||||
return self._format_docutils_params(
|
||||
fields,
|
||||
field_role="keyword",
|
||||
type_role="kwtype")
|
||||
fields, field_role='keyword', type_role='kwtype'
|
||||
)
|
||||
else:
|
||||
return self._format_fields(_('Keyword Arguments'), fields)
|
||||
|
||||
@ -770,7 +794,7 @@ class GoogleDocstring:
|
||||
_type = m.group('name')
|
||||
elif _xref_regex.match(_type):
|
||||
pos = _type.find('`')
|
||||
_type = _type[pos + 1:-1]
|
||||
_type = _type[pos + 1 : -1]
|
||||
_type = ' ' + _type if _type else ''
|
||||
_desc = self._strip_empty(_desc)
|
||||
_descs = ' ' + '\n '.join(_desc) if any(_desc) else ''
|
||||
@ -840,15 +864,13 @@ class GoogleDocstring:
|
||||
m = _single_colon_regex.search(source)
|
||||
if (i % 2) == 0 and m:
|
||||
found_colon = True
|
||||
colon = source[m.start(): m.end()]
|
||||
before_colon.append(source[:m.start()])
|
||||
after_colon.append(source[m.end():])
|
||||
colon = source[m.start() : m.end()]
|
||||
before_colon.append(source[: m.start()])
|
||||
after_colon.append(source[m.end() :])
|
||||
else:
|
||||
before_colon.append(source)
|
||||
|
||||
return ("".join(before_colon).strip(),
|
||||
colon,
|
||||
"".join(after_colon).strip())
|
||||
return ''.join(before_colon).strip(), colon, ''.join(after_colon).strip()
|
||||
|
||||
def _strip_empty(self, lines: list[str]) -> list[str]:
|
||||
if lines:
|
||||
@ -866,29 +888,35 @@ class GoogleDocstring:
|
||||
end = i
|
||||
break
|
||||
if start > 0 or end + 1 < len(lines):
|
||||
lines = lines[start:end + 1]
|
||||
lines = lines[start : end + 1]
|
||||
return lines
|
||||
|
||||
def _lookup_annotation(self, _name: str) -> str:
|
||||
if self._config.napoleon_attr_annotations:
|
||||
if self._what in ("module", "class", "exception") and self._obj:
|
||||
if self._what in ('module', 'class', 'exception') and self._obj:
|
||||
# cache the class annotations
|
||||
if not hasattr(self, "_annotations"):
|
||||
localns = getattr(self._config, "autodoc_type_aliases", {})
|
||||
localns.update(getattr(
|
||||
self._config, "napoleon_type_aliases", {},
|
||||
) or {})
|
||||
if not hasattr(self, '_annotations'):
|
||||
localns = getattr(self._config, 'autodoc_type_aliases', {})
|
||||
localns.update(
|
||||
getattr(
|
||||
self._config,
|
||||
'napoleon_type_aliases',
|
||||
{},
|
||||
)
|
||||
or {}
|
||||
)
|
||||
self._annotations = get_type_hints(self._obj, None, localns)
|
||||
if _name in self._annotations:
|
||||
return stringify_annotation(self._annotations[_name],
|
||||
'fully-qualified-except-typing')
|
||||
return stringify_annotation(
|
||||
self._annotations[_name], 'fully-qualified-except-typing'
|
||||
)
|
||||
# No annotation found
|
||||
return ""
|
||||
return ''
|
||||
|
||||
|
||||
def _recombine_set_tokens(tokens: list[str]) -> list[str]:
|
||||
token_queue = collections.deque(tokens)
|
||||
keywords = ("optional", "default")
|
||||
keywords = ('optional', 'default')
|
||||
|
||||
def takewhile_set(tokens: collections.deque[str]) -> Iterator[str]:
|
||||
open_braces = 0
|
||||
@ -899,7 +927,7 @@ def _recombine_set_tokens(tokens: list[str]) -> list[str]:
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
if token == ", ":
|
||||
if token == ', ':
|
||||
previous_token = token
|
||||
continue
|
||||
|
||||
@ -916,9 +944,9 @@ def _recombine_set_tokens(tokens: list[str]) -> list[str]:
|
||||
yield previous_token
|
||||
previous_token = None
|
||||
|
||||
if token == "{":
|
||||
if token == '{':
|
||||
open_braces += 1
|
||||
elif token == "}":
|
||||
elif token == '}':
|
||||
open_braces -= 1
|
||||
|
||||
yield token
|
||||
@ -933,9 +961,9 @@ def _recombine_set_tokens(tokens: list[str]) -> list[str]:
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
if token == "{":
|
||||
tokens.appendleft("{")
|
||||
yield "".join(takewhile_set(tokens))
|
||||
if token == '{':
|
||||
tokens.appendleft('{')
|
||||
yield ''.join(takewhile_set(tokens))
|
||||
else:
|
||||
yield token
|
||||
|
||||
@ -950,7 +978,7 @@ def _tokenize_type_spec(spec: str) -> list[str]:
|
||||
# for now
|
||||
other = item[8:]
|
||||
|
||||
return [default, " ", other]
|
||||
return [default, ' ', other]
|
||||
else:
|
||||
return [item]
|
||||
|
||||
@ -973,70 +1001,74 @@ def _token_type(token: str, location: str | None = None) -> str:
|
||||
else:
|
||||
return True
|
||||
|
||||
if token.startswith(" ") or token.endswith(" "):
|
||||
type_ = "delimiter"
|
||||
if token.startswith(' ') or token.endswith(' '):
|
||||
type_ = 'delimiter'
|
||||
elif (
|
||||
is_numeric(token) or
|
||||
(token.startswith("{") and token.endswith("}")) or
|
||||
(token.startswith('"') and token.endswith('"')) or
|
||||
(token.startswith("'") and token.endswith("'"))
|
||||
is_numeric(token)
|
||||
or (token.startswith('{') and token.endswith('}'))
|
||||
or (token.startswith('"') and token.endswith('"'))
|
||||
or (token.startswith("'") and token.endswith("'"))
|
||||
):
|
||||
type_ = "literal"
|
||||
elif token.startswith("{"):
|
||||
type_ = 'literal'
|
||||
elif token.startswith('{'):
|
||||
logger.warning(
|
||||
__("invalid value set (missing closing brace): %s"),
|
||||
__('invalid value set (missing closing brace): %s'),
|
||||
token,
|
||||
location=location,
|
||||
)
|
||||
type_ = "literal"
|
||||
elif token.endswith("}"):
|
||||
type_ = 'literal'
|
||||
elif token.endswith('}'):
|
||||
logger.warning(
|
||||
__("invalid value set (missing opening brace): %s"),
|
||||
__('invalid value set (missing opening brace): %s'),
|
||||
token,
|
||||
location=location,
|
||||
)
|
||||
type_ = "literal"
|
||||
type_ = 'literal'
|
||||
elif token.startswith(("'", '"')):
|
||||
logger.warning(
|
||||
__("malformed string literal (missing closing quote): %s"),
|
||||
__('malformed string literal (missing closing quote): %s'),
|
||||
token,
|
||||
location=location,
|
||||
)
|
||||
type_ = "literal"
|
||||
type_ = 'literal'
|
||||
elif token.endswith(("'", '"')):
|
||||
logger.warning(
|
||||
__("malformed string literal (missing opening quote): %s"),
|
||||
__('malformed string literal (missing opening quote): %s'),
|
||||
token,
|
||||
location=location,
|
||||
)
|
||||
type_ = "literal"
|
||||
elif token in ("optional", "default"):
|
||||
type_ = 'literal'
|
||||
elif token in ('optional', 'default'):
|
||||
# default is not a official keyword (yet) but supported by the
|
||||
# reference implementation (numpydoc) and widely used
|
||||
type_ = "control"
|
||||
type_ = 'control'
|
||||
elif _xref_regex.match(token):
|
||||
type_ = "reference"
|
||||
type_ = 'reference'
|
||||
else:
|
||||
type_ = "obj"
|
||||
type_ = 'obj'
|
||||
|
||||
return type_
|
||||
|
||||
|
||||
def _convert_numpy_type_spec(
|
||||
_type: str, location: str | None = None, translations: dict[str, str] | None = None,
|
||||
_type: str,
|
||||
location: str | None = None,
|
||||
translations: dict[str, str] | None = None,
|
||||
) -> str:
|
||||
if translations is None:
|
||||
translations = {}
|
||||
|
||||
def convert_obj(obj: str, translations: dict[str, str], default_translation: str) -> str:
|
||||
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
|
||||
if translation in _SINGLETONS and default_translation == ":class:`%s`":
|
||||
default_translation = ":obj:`%s`"
|
||||
elif translation == "..." and default_translation == ":class:`%s`":
|
||||
if translation in _SINGLETONS and default_translation == ':class:`%s`':
|
||||
default_translation = ':obj:`%s`'
|
||||
elif translation == '...' and default_translation == ':class:`%s`':
|
||||
# allow referencing the builtin ...
|
||||
default_translation = ":obj:`%s <Ellipsis>`"
|
||||
default_translation = ':obj:`%s <Ellipsis>`'
|
||||
|
||||
if _xref_regex.match(translation) is None:
|
||||
translation = default_translation % translation
|
||||
@ -1045,21 +1077,20 @@ def _convert_numpy_type_spec(
|
||||
|
||||
tokens = _tokenize_type_spec(_type)
|
||||
combined_tokens = _recombine_set_tokens(tokens)
|
||||
types = [
|
||||
(token, _token_type(token, location))
|
||||
for token in combined_tokens
|
||||
]
|
||||
types = [(token, _token_type(token, location)) for token in combined_tokens]
|
||||
|
||||
converters = {
|
||||
"literal": lambda x: "``%s``" % x,
|
||||
"obj": lambda x: convert_obj(x, translations, ":class:`%s`"),
|
||||
"control": lambda x: "*%s*" % x,
|
||||
"delimiter": lambda x: x,
|
||||
"reference": lambda x: x,
|
||||
'literal': lambda x: '``%s``' % x,
|
||||
'obj': lambda x: convert_obj(x, translations, ':class:`%s`'),
|
||||
'control': lambda x: '*%s*' % x,
|
||||
'delimiter': lambda x: x,
|
||||
'reference': lambda x: x,
|
||||
}
|
||||
|
||||
converted = "".join(converters.get(type_)(token) # type: ignore[misc]
|
||||
for token, type_ in types)
|
||||
converted = ''.join(
|
||||
converters.get(type_)(token) # type: ignore[misc]
|
||||
for token, type_ in types
|
||||
)
|
||||
|
||||
return converted
|
||||
|
||||
@ -1181,20 +1212,21 @@ class NumpyDocstring(GoogleDocstring):
|
||||
if filepath is None and name is None:
|
||||
return None
|
||||
elif filepath is None:
|
||||
filepath = ""
|
||||
filepath = ''
|
||||
|
||||
return f"{filepath}:docstring of {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(map(func, name.split(", ")))
|
||||
if ', ' in name:
|
||||
return ', '.join(map(func, name.split(', ')))
|
||||
else:
|
||||
return func(name)
|
||||
|
||||
def _consume_field(self, parse_type: bool = True, prefer_type: bool = False,
|
||||
) -> tuple[str, str, list[str]]:
|
||||
def _consume_field(
|
||||
self, parse_type: bool = True, prefer_type: bool = False
|
||||
) -> tuple[str, str, list[str]]:
|
||||
line = self._lines.next()
|
||||
if parse_type:
|
||||
_name, _, _type = self._partition_field_on_colon(line)
|
||||
@ -1221,8 +1253,9 @@ class NumpyDocstring(GoogleDocstring):
|
||||
_desc = self.__class__(_desc, self._config).lines()
|
||||
return _name, _type, _desc
|
||||
|
||||
def _consume_returns_section(self, preprocess_types: bool = False,
|
||||
) -> list[tuple[str, str, list[str]]]:
|
||||
def _consume_returns_section(
|
||||
self, preprocess_types: bool = False
|
||||
) -> list[tuple[str, str, list[str]]]:
|
||||
return self._consume_fields(prefer_type=True)
|
||||
|
||||
def _consume_section_header(self) -> str:
|
||||
@ -1234,12 +1267,16 @@ class NumpyDocstring(GoogleDocstring):
|
||||
|
||||
def _is_section_break(self) -> bool:
|
||||
line1, line2 = self._lines.get(0), self._lines.get(1)
|
||||
return (not self._lines or
|
||||
self._is_section_header() or
|
||||
(line1 == line2 == '') or
|
||||
(self._is_in_section and
|
||||
line1 and
|
||||
not self._is_indented(line1, self._section_indent)))
|
||||
return (
|
||||
not self._lines
|
||||
or self._is_section_header()
|
||||
or (line1 == line2 == '')
|
||||
or (
|
||||
self._is_in_section
|
||||
and line1
|
||||
and not self._is_indented(line1, self._section_indent)
|
||||
)
|
||||
)
|
||||
|
||||
def _is_section_header(self) -> bool:
|
||||
section, underline = self._lines.get(0), self._lines.get(1)
|
||||
@ -1312,7 +1349,7 @@ class NumpyDocstring(GoogleDocstring):
|
||||
return g[3], None
|
||||
else:
|
||||
return g[2], g[1]
|
||||
raise ValueError("%s is not a item name" % text)
|
||||
raise ValueError('%s is not a item name' % text)
|
||||
|
||||
def push_item(name: str | None, rest: list[str]) -> None:
|
||||
if not name:
|
||||
@ -1322,7 +1359,9 @@ class NumpyDocstring(GoogleDocstring):
|
||||
rest.clear()
|
||||
|
||||
def translate(
|
||||
func: str, description: list[str], role: str | None,
|
||||
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:
|
||||
@ -1334,8 +1373,8 @@ class NumpyDocstring(GoogleDocstring):
|
||||
return translated, description, role
|
||||
|
||||
groups = match.groupdict()
|
||||
role = groups["role"]
|
||||
new_func = groups["name"] or groups["name2"]
|
||||
role = groups['role']
|
||||
new_func = groups['name'] or groups['name2']
|
||||
|
||||
return new_func, description, role
|
||||
|
||||
@ -1347,9 +1386,9 @@ class NumpyDocstring(GoogleDocstring):
|
||||
continue
|
||||
|
||||
m = self._name_rgx.match(line)
|
||||
if m and line[m.end():].strip().startswith(':'):
|
||||
if m and line[m.end() :].strip().startswith(':'):
|
||||
push_item(current_func, rest)
|
||||
current_func, line = line[:m.end()], line[m.end():]
|
||||
current_func, line = line[: m.end()], line[m.end() :]
|
||||
rest = [line.split(':', 1)[1].strip()]
|
||||
if not rest[0]:
|
||||
rest = []
|
||||
@ -1383,7 +1422,7 @@ class NumpyDocstring(GoogleDocstring):
|
||||
lines += ['']
|
||||
lines += [link]
|
||||
else:
|
||||
lines[-1] += ", %s" % link
|
||||
lines[-1] += ', %s' % link
|
||||
if desc:
|
||||
lines += self._indent([' '.join(desc)])
|
||||
last_had_desc = True
|
||||
|
Loading…
Reference in New Issue
Block a user