Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #8004: napoleon_preprocess_types for Google style docstrings #8731

Merged
merged 1 commit into from
Jan 24, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -39,6 +39,8 @@ Features added
type
* #8573: napoleon: Allow to change the style of custom sections using
:confval:`napoleon_custom_styles`
* #8004: napoleon: Type definitions in Google style docstrings are rendered as
references when :confval:`napoleon_preprocess_types` enabled
* #6241: mathjax: Include mathjax.js only on the document using equations
* #8651: std domain: cross-reference for a rubric having inline item is broken
* #8681: viewcode: Support incremental build
31 changes: 27 additions & 4 deletions sphinx/ext/napoleon/docstring.py
Original file line number Diff line number Diff line change
@@ -59,6 +59,19 @@
_SINGLETONS = ("None", "True", "False", "Ellipsis")


def _convert_type_spec(_type: str, translations: Dict[str, str] = {}) -> str:
"""Convert type specification to reference in reST."""
if _type in translations:
return translations[_type]
else:
if _type == 'None':
return ':obj:`None`'
else:
return ':class:`%s`' % _type

return _type


class GoogleDocstring:
"""Convert Google style docstrings to reStructuredText.

@@ -265,6 +278,10 @@ def _consume_field(self, parse_type: bool = True, prefer_type: bool = False

if prefer_type and not _type:
_type, _name = _name, _type

if _type and self._config.napoleon_preprocess_types:
_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 = self.__class__(_descs, self._config).lines()
@@ -293,7 +310,8 @@ def _consume_inline_attribute(self) -> Tuple[str, List[str]]:
_descs = self.__class__(_descs, self._config).lines()
return _type, _descs

def _consume_returns_section(self) -> 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])
@@ -307,6 +325,10 @@ def _consume_returns_section(self) -> List[Tuple[str, str, List[str]]]:

_type = before

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,)]
else:
@@ -652,7 +674,7 @@ def _parse_custom_params_style_section(self, section: str) -> List[str]:
return self._format_fields(section, self._consume_fields())

def _parse_custom_returns_style_section(self, section: str) -> List[str]:
fields = self._consume_returns_section()
fields = self._consume_returns_section(preprocess_types=True)
return self._format_fields(section, fields)

def _parse_usage_section(self, section: str) -> List[str]:
@@ -778,7 +800,7 @@ def _parse_warns_section(self, section: str) -> List[str]:
return self._format_fields(_('Warns'), self._consume_fields())

def _parse_yields_section(self, section: str) -> List[str]:
fields = self._consume_returns_section()
fields = self._consume_returns_section(preprocess_types=True)
return self._format_fields(_('Yields'), fields)

def _partition_field_on_colon(self, line: str) -> Tuple[str, str, str]:
@@ -1170,7 +1192,8 @@ def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
_desc = self.__class__(_desc, self._config).lines()
return _name, _type, _desc

def _consume_returns_section(self) -> 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:
24 changes: 24 additions & 0 deletions tests/test_ext_napoleon_docstring.py
Original file line number Diff line number Diff line change
@@ -1167,6 +1167,30 @@ def test_pep526_annotations(self):
"""
self.assertEqual(expected, actual)

def test_preprocess_types(self):
docstring = """\
Do as you please

Yield:
str:Extended
"""
actual = str(GoogleDocstring(docstring))
expected = """\
Do as you please

:Yields: *str* -- Extended
"""
self.assertEqual(expected, actual)

config = Config(napoleon_preprocess_types=True)
actual = str(GoogleDocstring(docstring, config))
expected = """\
Do as you please

:Yields: :class:`str` -- Extended
"""
self.assertEqual(expected, actual)


class NumpyDocstringTest(BaseDocstringTest):
docstrings = [(