Skip to content

Commit

Permalink
Fix #7780: napoleon: multiple params declaration was wrongly recognized
Browse files Browse the repository at this point in the history
So far, napoleon converts multiple paramaters declrarations to single
paramaeter fields (`:param:` and `:type:`) unexpectedly.  As a result,
the output seems broken.

This converts it to multiple parameter fields (a pair of field for each
parameter declration) to build parameter successfully.

Note: The conversion rule is available only when napoleon_use_params=True.
  • Loading branch information
tk0miya committed Aug 7, 2020
1 parent 92a134b commit d6ef816
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -78,6 +78,8 @@ Bugs fixed
module has submodules
* #4258: napoleon: decorated special methods are not shown
* #7799: napoleon: parameters are not escaped for combined params in numpydoc
* #7780: napoleon: multiple paramaters declaration in numpydoc was wrongly
recognized when napoleon_use_params=True
* #7715: LaTeX: ``numfig_secnum_depth > 1`` leads to wrong figure links
* #7846: html theme: XML-invalid files were generated
* #7894: gettext: Wrong source info is shown when using rst_epilog
Expand Down
16 changes: 11 additions & 5 deletions sphinx/ext/napoleon/docstring.py
Expand Up @@ -266,14 +266,18 @@ def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
_descs = self.__class__(_descs, self._config).lines()
return _name, _type, _descs

def _consume_fields(self, parse_type: bool = True, prefer_type: 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 = []
while not self._is_section_break():
_name, _type, _desc = self._consume_field(parse_type, prefer_type)
if _name or _type or _desc:
fields.append((_name, _type, _desc,))
if multiple and _name:
for name in _name.split(","):
fields.append((name.strip(), _type, _desc))
else:
if _name or _type or _desc:
fields.append((_name, _type, _desc,))
return fields

def _consume_inline_attribute(self) -> Tuple[str, List[str]]:
Expand Down Expand Up @@ -681,10 +685,12 @@ def _parse_other_parameters_section(self, section: str) -> List[str]:
return self._format_fields(_('Other Parameters'), self._consume_fields())

def _parse_parameters_section(self, section: str) -> List[str]:
fields = self._consume_fields()
if self._config.napoleon_use_param:
# Allow to declare multiple parameters at once (ex: x, y: int)
fields = self._consume_fields(multiple=True)
return self._format_docutils_params(fields)
else:
fields = self._consume_fields()
return self._format_fields(_('Parameters'), fields)

def _parse_raises_section(self, section: str) -> List[str]:
Expand Down
26 changes: 26 additions & 0 deletions tests/test_ext_napoleon_docstring.py
Expand Up @@ -1337,6 +1337,32 @@ def test_parameters_with_class_reference(self):
expected = """\
:param param1:
:type param1: :class:`MyClass <name.space.MyClass>` instance
"""
self.assertEqual(expected, actual)

def test_multiple_parameters(self):
docstring = """\
Parameters
----------
x1, x2 : array_like
Input arrays, description of ``x1``, ``x2``.
"""

config = Config(napoleon_use_param=False)
actual = str(NumpyDocstring(docstring, config))
expected = """\
:Parameters: **x1, x2** (*array_like*) -- Input arrays, description of ``x1``, ``x2``.
"""
self.assertEqual(expected, actual)

config = Config(napoleon_use_param=True)
actual = str(NumpyDocstring(dedent(docstring), config))
expected = """\
:param x1: Input arrays, description of ``x1``, ``x2``.
:type x1: array_like
:param x2: Input arrays, description of ``x1``, ``x2``.
:type x2: array_like
"""
self.assertEqual(expected, actual)

Expand Down

0 comments on commit d6ef816

Please sign in to comment.