mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Fix #2227: [Napoleon] Fixes issue in which bulleted lists in parameter descriptions could cause the sphinx builder to fail
This commit is contained in:
@@ -27,6 +27,11 @@ _google_section_regex = re.compile(r'^(\s|\w)+:\s*$')
|
||||
_google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.+?)\s*\)')
|
||||
_numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$')
|
||||
_xref_regex = re.compile(r'(:\w+:\S+:`.+?`|:\S+:`.+?`|`.+?`)')
|
||||
_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*$)')
|
||||
|
||||
|
||||
class GoogleDocstring(UnicodeMixin):
|
||||
@@ -349,6 +354,8 @@ class GoogleDocstring(UnicodeMixin):
|
||||
field = ''
|
||||
|
||||
if has_desc:
|
||||
if self._is_list(_desc):
|
||||
return [field, ''] + _desc
|
||||
return [field + _desc[0]] + _desc[1:]
|
||||
else:
|
||||
return [field]
|
||||
@@ -408,6 +415,23 @@ class GoogleDocstring(UnicodeMixin):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _is_list(self, lines):
|
||||
if not lines:
|
||||
return False
|
||||
if _bullet_list_regex.match(lines[0]):
|
||||
return True
|
||||
if _enumerated_list_regex.match(lines[0]):
|
||||
return True
|
||||
if len(lines) < 2 or lines[0].endswith('::'):
|
||||
return False
|
||||
indent = self._get_indent(lines[0])
|
||||
next_indent = indent
|
||||
for line in lines[1:]:
|
||||
if line:
|
||||
next_indent = self._get_indent(line)
|
||||
break
|
||||
return next_indent > indent
|
||||
|
||||
def _is_section_header(self):
|
||||
section = self._line_iter.peek().lower()
|
||||
match = _google_section_regex.match(section)
|
||||
@@ -530,10 +554,18 @@ class GoogleDocstring(UnicodeMixin):
|
||||
if self._config.napoleon_use_param:
|
||||
lines = []
|
||||
for _name, _type, _desc in fields:
|
||||
_desc = self._strip_empty(_desc)
|
||||
if any(_desc):
|
||||
if self._is_list(_desc):
|
||||
_desc = [''] + _desc
|
||||
field = ':param %s: ' % _name
|
||||
lines.extend(self._format_block(field, _desc))
|
||||
else:
|
||||
lines.append(':param %s:' % _name)
|
||||
|
||||
if _type:
|
||||
lines.append(':type %s: %s' % (_name, _type))
|
||||
|
||||
return lines + ['']
|
||||
else:
|
||||
return self._format_fields('Parameters', fields)
|
||||
@@ -777,10 +809,11 @@ class NumpyDocstring(GoogleDocstring):
|
||||
_name, _type = line, ''
|
||||
_name, _type = _name.strip(), _type.strip()
|
||||
_name = self._escape_args_and_kwargs(_name)
|
||||
|
||||
if prefer_type and not _type:
|
||||
_type, _name = _name, _type
|
||||
indent = self._get_indent(line)
|
||||
_desc = self._dedent(self._consume_indented_block(indent + 1))
|
||||
indent = self._get_indent(line) + 1
|
||||
_desc = self._dedent(self._consume_indented_block(indent))
|
||||
_desc = self.__class__(_desc, self._config).lines()
|
||||
return _name, _type, _desc
|
||||
|
||||
|
||||
@@ -280,14 +280,11 @@ This class should only be used by runtimes.
|
||||
|
||||
:param runtime: Use it to access the environment.
|
||||
It is available in XBlock code as ``self.runtime``.
|
||||
|
||||
:type runtime: :class:`Runtime`
|
||||
:param field_data: Interface used by the XBlock
|
||||
fields to access their data from wherever it is persisted.
|
||||
|
||||
:type field_data: :class:`FieldData`
|
||||
:param scope_ids: Identifiers needed to resolve scopes.
|
||||
|
||||
:type scope_ids: :class:`ScopeIds`
|
||||
"""
|
||||
self.assertEqual(expected, actual)
|
||||
@@ -615,6 +612,285 @@ Summary line
|
||||
actual = str(GoogleDocstring(docstring))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_list_in_parameter_description(self):
|
||||
docstring = """One line summary.
|
||||
|
||||
Parameters:
|
||||
no_list (int):
|
||||
one_bullet_empty (int):
|
||||
*
|
||||
one_bullet_single_line (int):
|
||||
- first line
|
||||
one_bullet_two_lines (int):
|
||||
+ first line
|
||||
continued
|
||||
two_bullets_single_line (int):
|
||||
- first line
|
||||
- second line
|
||||
two_bullets_two_lines (int):
|
||||
* first line
|
||||
continued
|
||||
* second line
|
||||
continued
|
||||
one_enumeration_single_line (int):
|
||||
1. first line
|
||||
one_enumeration_two_lines (int):
|
||||
1) first line
|
||||
continued
|
||||
two_enumerations_one_line (int):
|
||||
(iii) first line
|
||||
(iv) second line
|
||||
two_enumerations_two_lines (int):
|
||||
a. first line
|
||||
continued
|
||||
b. second line
|
||||
continued
|
||||
one_definition_one_line (int):
|
||||
item 1
|
||||
first line
|
||||
one_definition_two_lines (int):
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
two_definitions_one_line (int):
|
||||
item 1
|
||||
first line
|
||||
item 2
|
||||
second line
|
||||
two_definitions_two_lines (int):
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
item 2
|
||||
second line
|
||||
continued
|
||||
one_definition_blank_line (int):
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
two_definitions_blank_lines (int):
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
item 2
|
||||
|
||||
second line
|
||||
|
||||
extra second line
|
||||
|
||||
definition_after_inline_text (int): text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
|
||||
definition_after_normal_text (int):
|
||||
text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
"""
|
||||
|
||||
expected = """One line summary.
|
||||
|
||||
:param no_list:
|
||||
:type no_list: int
|
||||
:param one_bullet_empty:
|
||||
*
|
||||
:type one_bullet_empty: int
|
||||
:param one_bullet_single_line:
|
||||
- first line
|
||||
:type one_bullet_single_line: int
|
||||
:param one_bullet_two_lines:
|
||||
+ first line
|
||||
continued
|
||||
:type one_bullet_two_lines: int
|
||||
:param two_bullets_single_line:
|
||||
- first line
|
||||
- second line
|
||||
:type two_bullets_single_line: int
|
||||
:param two_bullets_two_lines:
|
||||
* first line
|
||||
continued
|
||||
* second line
|
||||
continued
|
||||
:type two_bullets_two_lines: int
|
||||
:param one_enumeration_single_line:
|
||||
1. first line
|
||||
:type one_enumeration_single_line: int
|
||||
:param one_enumeration_two_lines:
|
||||
1) first line
|
||||
continued
|
||||
:type one_enumeration_two_lines: int
|
||||
:param two_enumerations_one_line:
|
||||
(iii) first line
|
||||
(iv) second line
|
||||
:type two_enumerations_one_line: int
|
||||
:param two_enumerations_two_lines:
|
||||
a. first line
|
||||
continued
|
||||
b. second line
|
||||
continued
|
||||
:type two_enumerations_two_lines: int
|
||||
:param one_definition_one_line:
|
||||
item 1
|
||||
first line
|
||||
:type one_definition_one_line: int
|
||||
:param one_definition_two_lines:
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
:type one_definition_two_lines: int
|
||||
:param two_definitions_one_line:
|
||||
item 1
|
||||
first line
|
||||
item 2
|
||||
second line
|
||||
:type two_definitions_one_line: int
|
||||
:param two_definitions_two_lines:
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
item 2
|
||||
second line
|
||||
continued
|
||||
:type two_definitions_two_lines: int
|
||||
:param one_definition_blank_line:
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
:type one_definition_blank_line: int
|
||||
:param two_definitions_blank_lines:
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
item 2
|
||||
|
||||
second line
|
||||
|
||||
extra second line
|
||||
:type two_definitions_blank_lines: int
|
||||
:param definition_after_inline_text: text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
:type definition_after_inline_text: int
|
||||
:param definition_after_normal_text: text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
:type definition_after_normal_text: int
|
||||
"""
|
||||
config = Config(napoleon_use_param=True)
|
||||
actual = str(GoogleDocstring(docstring, config))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
expected = """One line summary.
|
||||
|
||||
:Parameters: * **no_list** (*int*)
|
||||
* **one_bullet_empty** (*int*) --
|
||||
|
||||
*
|
||||
* **one_bullet_single_line** (*int*) --
|
||||
|
||||
- first line
|
||||
* **one_bullet_two_lines** (*int*) --
|
||||
|
||||
+ first line
|
||||
continued
|
||||
* **two_bullets_single_line** (*int*) --
|
||||
|
||||
- first line
|
||||
- second line
|
||||
* **two_bullets_two_lines** (*int*) --
|
||||
|
||||
* first line
|
||||
continued
|
||||
* second line
|
||||
continued
|
||||
* **one_enumeration_single_line** (*int*) --
|
||||
|
||||
1. first line
|
||||
* **one_enumeration_two_lines** (*int*) --
|
||||
|
||||
1) first line
|
||||
continued
|
||||
* **two_enumerations_one_line** (*int*) --
|
||||
|
||||
(iii) first line
|
||||
(iv) second line
|
||||
* **two_enumerations_two_lines** (*int*) --
|
||||
|
||||
a. first line
|
||||
continued
|
||||
b. second line
|
||||
continued
|
||||
* **one_definition_one_line** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
* **one_definition_two_lines** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
* **two_definitions_one_line** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
item 2
|
||||
second line
|
||||
* **two_definitions_two_lines** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
item 2
|
||||
second line
|
||||
continued
|
||||
* **one_definition_blank_line** (*int*) --
|
||||
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
* **two_definitions_blank_lines** (*int*) --
|
||||
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
item 2
|
||||
|
||||
second line
|
||||
|
||||
extra second line
|
||||
* **definition_after_inline_text** (*int*) -- text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
* **definition_after_normal_text** (*int*) -- text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
"""
|
||||
config = Config(napoleon_use_param=False)
|
||||
actual = str(GoogleDocstring(docstring, config))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
|
||||
class NumpyDocstringTest(BaseDocstringTest):
|
||||
docstrings = [(
|
||||
@@ -1194,3 +1470,269 @@ body
|
||||
for docstring, expected in docstrings:
|
||||
actual = str(NumpyDocstring(docstring))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_list_in_parameter_description(self):
|
||||
docstring = """One line summary.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
no_list : int
|
||||
one_bullet_empty : int
|
||||
*
|
||||
one_bullet_single_line : int
|
||||
- first line
|
||||
one_bullet_two_lines : int
|
||||
+ first line
|
||||
continued
|
||||
two_bullets_single_line : int
|
||||
- first line
|
||||
- second line
|
||||
two_bullets_two_lines : int
|
||||
* first line
|
||||
continued
|
||||
* second line
|
||||
continued
|
||||
one_enumeration_single_line : int
|
||||
1. first line
|
||||
one_enumeration_two_lines : int
|
||||
1) first line
|
||||
continued
|
||||
two_enumerations_one_line : int
|
||||
(iii) first line
|
||||
(iv) second line
|
||||
two_enumerations_two_lines : int
|
||||
a. first line
|
||||
continued
|
||||
b. second line
|
||||
continued
|
||||
one_definition_one_line : int
|
||||
item 1
|
||||
first line
|
||||
one_definition_two_lines : int
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
two_definitions_one_line : int
|
||||
item 1
|
||||
first line
|
||||
item 2
|
||||
second line
|
||||
two_definitions_two_lines : int
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
item 2
|
||||
second line
|
||||
continued
|
||||
one_definition_blank_line : int
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
two_definitions_blank_lines : int
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
item 2
|
||||
|
||||
second line
|
||||
|
||||
extra second line
|
||||
|
||||
definition_after_normal_text : int
|
||||
text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
"""
|
||||
|
||||
expected = """One line summary.
|
||||
|
||||
:param no_list:
|
||||
:type no_list: int
|
||||
:param one_bullet_empty:
|
||||
*
|
||||
:type one_bullet_empty: int
|
||||
:param one_bullet_single_line:
|
||||
- first line
|
||||
:type one_bullet_single_line: int
|
||||
:param one_bullet_two_lines:
|
||||
+ first line
|
||||
continued
|
||||
:type one_bullet_two_lines: int
|
||||
:param two_bullets_single_line:
|
||||
- first line
|
||||
- second line
|
||||
:type two_bullets_single_line: int
|
||||
:param two_bullets_two_lines:
|
||||
* first line
|
||||
continued
|
||||
* second line
|
||||
continued
|
||||
:type two_bullets_two_lines: int
|
||||
:param one_enumeration_single_line:
|
||||
1. first line
|
||||
:type one_enumeration_single_line: int
|
||||
:param one_enumeration_two_lines:
|
||||
1) first line
|
||||
continued
|
||||
:type one_enumeration_two_lines: int
|
||||
:param two_enumerations_one_line:
|
||||
(iii) first line
|
||||
(iv) second line
|
||||
:type two_enumerations_one_line: int
|
||||
:param two_enumerations_two_lines:
|
||||
a. first line
|
||||
continued
|
||||
b. second line
|
||||
continued
|
||||
:type two_enumerations_two_lines: int
|
||||
:param one_definition_one_line:
|
||||
item 1
|
||||
first line
|
||||
:type one_definition_one_line: int
|
||||
:param one_definition_two_lines:
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
:type one_definition_two_lines: int
|
||||
:param two_definitions_one_line:
|
||||
item 1
|
||||
first line
|
||||
item 2
|
||||
second line
|
||||
:type two_definitions_one_line: int
|
||||
:param two_definitions_two_lines:
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
item 2
|
||||
second line
|
||||
continued
|
||||
:type two_definitions_two_lines: int
|
||||
:param one_definition_blank_line:
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
:type one_definition_blank_line: int
|
||||
:param two_definitions_blank_lines:
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
item 2
|
||||
|
||||
second line
|
||||
|
||||
extra second line
|
||||
:type two_definitions_blank_lines: int
|
||||
:param definition_after_normal_text: text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
:type definition_after_normal_text: int
|
||||
"""
|
||||
config = Config(napoleon_use_param=True)
|
||||
actual = str(NumpyDocstring(docstring, config))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
expected = """One line summary.
|
||||
|
||||
:Parameters: * **no_list** (*int*)
|
||||
* **one_bullet_empty** (*int*) --
|
||||
|
||||
*
|
||||
* **one_bullet_single_line** (*int*) --
|
||||
|
||||
- first line
|
||||
* **one_bullet_two_lines** (*int*) --
|
||||
|
||||
+ first line
|
||||
continued
|
||||
* **two_bullets_single_line** (*int*) --
|
||||
|
||||
- first line
|
||||
- second line
|
||||
* **two_bullets_two_lines** (*int*) --
|
||||
|
||||
* first line
|
||||
continued
|
||||
* second line
|
||||
continued
|
||||
* **one_enumeration_single_line** (*int*) --
|
||||
|
||||
1. first line
|
||||
* **one_enumeration_two_lines** (*int*) --
|
||||
|
||||
1) first line
|
||||
continued
|
||||
* **two_enumerations_one_line** (*int*) --
|
||||
|
||||
(iii) first line
|
||||
(iv) second line
|
||||
* **two_enumerations_two_lines** (*int*) --
|
||||
|
||||
a. first line
|
||||
continued
|
||||
b. second line
|
||||
continued
|
||||
* **one_definition_one_line** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
* **one_definition_two_lines** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
* **two_definitions_one_line** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
item 2
|
||||
second line
|
||||
* **two_definitions_two_lines** (*int*) --
|
||||
|
||||
item 1
|
||||
first line
|
||||
continued
|
||||
item 2
|
||||
second line
|
||||
continued
|
||||
* **one_definition_blank_line** (*int*) --
|
||||
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
* **two_definitions_blank_lines** (*int*) --
|
||||
|
||||
item 1
|
||||
|
||||
first line
|
||||
|
||||
extra first line
|
||||
|
||||
item 2
|
||||
|
||||
second line
|
||||
|
||||
extra second line
|
||||
* **definition_after_normal_text** (*int*) -- text line
|
||||
|
||||
item 1
|
||||
first line
|
||||
"""
|
||||
config = Config(napoleon_use_param=False)
|
||||
actual = str(NumpyDocstring(docstring, config))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
Reference in New Issue
Block a user