Skip to content

Commit

Permalink
feat: Add option to Google parser allowing to parse Returns sections …
Browse files Browse the repository at this point in the history
…with or without multiple items

PR #196: #196
  • Loading branch information
AntoineD authored Aug 21, 2023
1 parent a357d4f commit 65fee70
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 2 deletions.
3 changes: 3 additions & 0 deletions docs/docstrings.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ The parser accepts a few options:
These flags are used to alter the behavior of [doctest][] when testing docstrings,
and should not be visible in your docs. Default: true.
- `warn_unknown_params`: Warn about parameters documented in docstrings that do not appear in the signature. Default: true.
- `returns_multiple_items`: Parse Returns sections as if they contain multiple items.
It means that continuation lines must be indented. Default: true.

Sections are written like this:

Expand Down Expand Up @@ -1497,6 +1499,7 @@ Option | Description | Google
`trim_doctest_flags` | Trim doctest flags. | ✅ | ✅ | [][issue-trim-doctest-flags-sphinx]
`warn_unknown_params` | Warn about unknown params. | ✅ | ✅ | [][issue-warn-unknown-params-sphinx]
`allow_section_blank_line` | Allow blank line in sections. | / | ✅ | /
`returns_multiple_items` | Parse multiple items in Returns sections. | ✅ | / | /

[issue-ignore-init-summary-sphinx]: https://github.com/mkdocstrings/griffe/issues/45
[issue-trim-doctest-flags-sphinx]: https://github.com/mkdocstrings/griffe/issues/49
Expand Down
6 changes: 6 additions & 0 deletions docs/schema-docstrings-options.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
"markdownDescription": "https://mkdocstrings.github.io/griffe/reference/griffe/docstrings/google/#griffe.docstrings.google.parse",
"type": "boolean",
"default": true
},
"returns_multiple_items": {
"title": "Whether the `Returns` section has multiple items.",
"markdownDescription": "https://mkdocstrings.github.io/griffe/reference/griffe/docstrings/google/#griffe.docstrings.google.parse",
"type": "boolean",
"default": true
}
},
"additionalProperties": false
Expand Down
11 changes: 10 additions & 1 deletion src/griffe/docstrings/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,10 +459,16 @@ def _read_returns_section(
docstring: Docstring,
*,
offset: int,
returns_multiple_items: bool,
**options: Any, # noqa: ARG001
) -> tuple[DocstringSectionReturns | None, int]:
returns = []
block, new_offset = _read_block_items(docstring, offset=offset)

if returns_multiple_items:
block, new_offset = _read_block_items(docstring, offset=offset)
else:
one_block, new_offset = _read_block(docstring, offset=offset)
block = [(new_offset, one_block.splitlines())]

for index, (line_number, return_lines) in enumerate(block):
match = _RE_NAME_ANNOTATION_DESCRIPTION.match(return_lines[0])
Expand Down Expand Up @@ -731,6 +737,7 @@ def parse(
*,
ignore_init_summary: bool = False,
trim_doctest_flags: bool = True,
returns_multiple_items: bool = True,
**options: Any,
) -> list[DocstringSection]:
"""Parse a docstring.
Expand All @@ -742,6 +749,7 @@ def parse(
docstring: The docstring to parse.
ignore_init_summary: Whether to ignore the summary in `__init__` methods' docstrings.
trim_doctest_flags: Whether to remove doctest flags from Python example blocks.
returns_multiple_items: Whether the `Returns` section has multiple items.
**options: Additional parsing options.
Returns:
Expand All @@ -756,6 +764,7 @@ def parse(
options = {
"ignore_init_summary": ignore_init_summary,
"trim_doctest_flags": trim_doctest_flags,
"returns_multiple_items": returns_multiple_items,
**options,
}

Expand Down
73 changes: 72 additions & 1 deletion tests/test_docstrings/test_google.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pytest

from griffe.dataclasses import Attribute, Class, Docstring, Function, Module, Parameter, Parameters
from griffe.docstrings.dataclasses import DocstringSectionKind
from griffe.docstrings.dataclasses import DocstringReturn, DocstringSectionKind
from griffe.docstrings.utils import parse_annotation
from griffe.expressions import ExprName

Expand Down Expand Up @@ -1359,3 +1359,74 @@ def test_single_line_with_trailing_whitespace(parse_google: ParserType) -> None:
assert len(sections) == 1
assert sections[0].kind is DocstringSectionKind.text
assert not warnings


@pytest.mark.parametrize(
("returns_multiple_items", "return_annotation", "expected"),
[
(
False,
None,
[DocstringReturn("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation=None)],
),
(
False,
"tuple[int, int]",
[DocstringReturn("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation="tuple[int, int]")],
),
(
True,
None,
[
DocstringReturn("", description="XXXXXXX\nYYYYYYY", annotation=None),
DocstringReturn("", description="ZZZZZZZ", annotation=None),
],
),
(
True,
"tuple[int,int]",
[
DocstringReturn("", description="XXXXXXX\nYYYYYYY", annotation="int"),
DocstringReturn("", description="ZZZZZZZ", annotation="int"),
],
),
],
)
def test_parse_returns_multiple_items(
parse_google: ParserType,
returns_multiple_items: bool,
return_annotation: str,
expected: list[DocstringReturn],
) -> None:
"""Parse Returns section with and without multiple items.
Parameters:
parse_google: Fixture parser.
returns_multiple_items: Whether the `Returns` section has multiple items.
return_annotation: The return annotation of the function to parse.
expected: The expected value of the parsed Returns section.
"""
parent = (
Function("func", returns=parse_annotation(return_annotation, Docstring("d", parent=Function("f"))))
if return_annotation is not None
else None
)
docstring = """
Returns:
XXXXXXX
YYYYYYY
ZZZZZZZ
"""
sections, _ = parse_google(
docstring,
returns_multiple_items=returns_multiple_items,
parent=parent,
)

assert len(sections) == 1
assert len(sections[0].value) == len(expected)

for annotated, expected_ in zip(sections[0].value, expected):
assert annotated.name == expected_.name
assert str(annotated.annotation) == str(expected_.annotation)
assert annotated.description == expected_.description

0 comments on commit 65fee70

Please sign in to comment.