mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Closes #1904: [Napoleon] parses restructuredtext references in fields/params BEFORE splitting on colon
This commit is contained in:
@@ -23,8 +23,8 @@ from sphinx.util.pycompat import UnicodeMixin
|
|||||||
|
|
||||||
|
|
||||||
_directive_regex = re.compile(r'\.\. \S+::')
|
_directive_regex = re.compile(r'\.\. \S+::')
|
||||||
_google_untyped_arg_regex = re.compile(r'(.+)\s*(?<!:):(?!:)\s*(.*)')
|
_google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.+?)\s*\)')
|
||||||
_google_typed_arg_regex = re.compile(r'(.+)\((.+)\)\s*(?<!:):(?!:)\s*(.*)')
|
_xref_regex = re.compile(r'(:\w+:\S+:`.+?`|:\S+:`.+?`|`.+?`)')
|
||||||
|
|
||||||
|
|
||||||
class GoogleDocstring(UnicodeMixin):
|
class GoogleDocstring(UnicodeMixin):
|
||||||
@@ -202,20 +202,14 @@ class GoogleDocstring(UnicodeMixin):
|
|||||||
def _consume_field(self, parse_type=True, prefer_type=False):
|
def _consume_field(self, parse_type=True, prefer_type=False):
|
||||||
line = next(self._line_iter)
|
line = next(self._line_iter)
|
||||||
|
|
||||||
match = None
|
before, colon, after = self._partition_field_on_colon(line)
|
||||||
_name, _type, _desc = line.strip(), '', ''
|
_name, _type, _desc = before, '', after
|
||||||
if parse_type:
|
|
||||||
match = _google_typed_arg_regex.match(line)
|
|
||||||
if match:
|
|
||||||
_name = match.group(1).strip()
|
|
||||||
_type = match.group(2).strip()
|
|
||||||
_desc = match.group(3).strip()
|
|
||||||
|
|
||||||
if not match:
|
if parse_type:
|
||||||
match = _google_untyped_arg_regex.match(line)
|
match = _google_typed_arg_regex.match(before)
|
||||||
if match:
|
if match:
|
||||||
_name = match.group(1).strip()
|
_name = match.group(1)
|
||||||
_desc = match.group(2).strip()
|
_type = match.group(2)
|
||||||
|
|
||||||
if _name[:2] == '**':
|
if _name[:2] == '**':
|
||||||
_name = r'\*\*'+_name[2:]
|
_name = r'\*\*'+_name[2:]
|
||||||
@@ -241,20 +235,21 @@ class GoogleDocstring(UnicodeMixin):
|
|||||||
def _consume_returns_section(self):
|
def _consume_returns_section(self):
|
||||||
lines = self._dedent(self._consume_to_next_section())
|
lines = self._dedent(self._consume_to_next_section())
|
||||||
if lines:
|
if lines:
|
||||||
|
before, colon, after = self._partition_field_on_colon(lines[0])
|
||||||
_name, _type, _desc = '', '', lines
|
_name, _type, _desc = '', '', lines
|
||||||
match = _google_typed_arg_regex.match(lines[0])
|
|
||||||
if match:
|
if colon:
|
||||||
_name = match.group(1).strip()
|
if after:
|
||||||
_type = match.group(2).strip()
|
_desc = [after] + lines[1:]
|
||||||
_desc = match.group(3).strip()
|
|
||||||
else:
|
else:
|
||||||
match = _google_untyped_arg_regex.match(lines[0])
|
_desc = lines[1:]
|
||||||
|
|
||||||
|
match = _google_typed_arg_regex.match(before)
|
||||||
if match:
|
if match:
|
||||||
_type = match.group(1).strip()
|
_name = match.group(1)
|
||||||
_desc = match.group(2).strip()
|
_type = match.group(2)
|
||||||
if match:
|
else:
|
||||||
lines[0] = _desc
|
_type = before
|
||||||
_desc = lines
|
|
||||||
|
|
||||||
_desc = self.__class__(_desc, self._config).lines()
|
_desc = self.__class__(_desc, self._config).lines()
|
||||||
return [(_name, _type, _desc,)]
|
return [(_name, _type, _desc,)]
|
||||||
@@ -593,6 +588,27 @@ class GoogleDocstring(UnicodeMixin):
|
|||||||
fields = self._consume_returns_section()
|
fields = self._consume_returns_section()
|
||||||
return self._format_fields('Yields', fields)
|
return self._format_fields('Yields', fields)
|
||||||
|
|
||||||
|
def _partition_field_on_colon(self, line):
|
||||||
|
before_colon = []
|
||||||
|
after_colon = []
|
||||||
|
colon = ''
|
||||||
|
found_colon = False
|
||||||
|
for i, source in enumerate(_xref_regex.split(line)):
|
||||||
|
if found_colon:
|
||||||
|
after_colon.append(source)
|
||||||
|
else:
|
||||||
|
if (i % 2) == 0 and ":" in source:
|
||||||
|
found_colon = True
|
||||||
|
before, colon, after = source.partition(":")
|
||||||
|
before_colon.append(before)
|
||||||
|
after_colon.append(after)
|
||||||
|
else:
|
||||||
|
before_colon.append(source)
|
||||||
|
|
||||||
|
return ("".join(before_colon).strip(),
|
||||||
|
colon,
|
||||||
|
"".join(after_colon).strip())
|
||||||
|
|
||||||
def _strip_empty(self, lines):
|
def _strip_empty(self, lines):
|
||||||
if lines:
|
if lines:
|
||||||
start = -1
|
start = -1
|
||||||
@@ -719,7 +735,7 @@ class NumpyDocstring(GoogleDocstring):
|
|||||||
def _consume_field(self, parse_type=True, prefer_type=False):
|
def _consume_field(self, parse_type=True, prefer_type=False):
|
||||||
line = next(self._line_iter)
|
line = next(self._line_iter)
|
||||||
if parse_type:
|
if parse_type:
|
||||||
_name, _, _type = line.partition(':')
|
_name, _, _type = self._partition_field_on_colon(line)
|
||||||
if not _name:
|
if not _name:
|
||||||
_type = line
|
_type = line
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -356,6 +356,22 @@ Returns:
|
|||||||
:returns: an example instance
|
:returns: an example instance
|
||||||
if available, None if not available.
|
if available, None if not available.
|
||||||
:rtype: :py:class:`~.module.submodule.SomeClass`
|
:rtype: :py:class:`~.module.submodule.SomeClass`
|
||||||
|
"""
|
||||||
|
actual = str(GoogleDocstring(docstring))
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_xrefs_in_return_type(self):
|
||||||
|
docstring = """Example Function
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`numpy.ndarray`: A :math:`n \\times 2` array containing
|
||||||
|
a bunch of math items
|
||||||
|
"""
|
||||||
|
expected = """Example Function
|
||||||
|
|
||||||
|
:returns: A :math:`n \\times 2` array containing
|
||||||
|
a bunch of math items
|
||||||
|
:rtype: :class:`numpy.ndarray`
|
||||||
"""
|
"""
|
||||||
actual = str(GoogleDocstring(docstring))
|
actual = str(GoogleDocstring(docstring))
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
@@ -696,3 +712,25 @@ arg_ : type
|
|||||||
actual = str(NumpyDocstring(docstring, config, app, "class"))
|
actual = str(NumpyDocstring(docstring, config, app, "class"))
|
||||||
|
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_xrefs_in_return_type(self):
|
||||||
|
docstring = """
|
||||||
|
Example Function
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
:class:`numpy.ndarray`
|
||||||
|
A :math:`n \\times 2` array containing
|
||||||
|
a bunch of math items
|
||||||
|
"""
|
||||||
|
expected = """
|
||||||
|
Example Function
|
||||||
|
|
||||||
|
:returns: A :math:`n \\times 2` array containing
|
||||||
|
a bunch of math items
|
||||||
|
:rtype: :class:`numpy.ndarray`
|
||||||
|
"""
|
||||||
|
config = Config()
|
||||||
|
app = mock.Mock()
|
||||||
|
actual = str(NumpyDocstring(docstring, config, app, "method"))
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|||||||
Reference in New Issue
Block a user