Skip to content

Commit 65fee70

Browse files
authored
feat: Add option to Google parser allowing to parse Returns sections with or without multiple items
PR #196: #196
1 parent a357d4f commit 65fee70

4 files changed

Lines changed: 91 additions & 2 deletions

File tree

docs/docstrings.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ The parser accepts a few options:
3434
These flags are used to alter the behavior of [doctest][] when testing docstrings,
3535
and should not be visible in your docs. Default: true.
3636
- `warn_unknown_params`: Warn about parameters documented in docstrings that do not appear in the signature. Default: true.
37+
- `returns_multiple_items`: Parse Returns sections as if they contain multiple items.
38+
It means that continuation lines must be indented. Default: true.
3739

3840
Sections are written like this:
3941

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

15011504
[issue-ignore-init-summary-sphinx]: https://github.com/mkdocstrings/griffe/issues/45
15021505
[issue-trim-doctest-flags-sphinx]: https://github.com/mkdocstrings/griffe/issues/49

docs/schema-docstrings-options.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
"markdownDescription": "https://mkdocstrings.github.io/griffe/reference/griffe/docstrings/google/#griffe.docstrings.google.parse",
1515
"type": "boolean",
1616
"default": true
17+
},
18+
"returns_multiple_items": {
19+
"title": "Whether the `Returns` section has multiple items.",
20+
"markdownDescription": "https://mkdocstrings.github.io/griffe/reference/griffe/docstrings/google/#griffe.docstrings.google.parse",
21+
"type": "boolean",
22+
"default": true
1723
}
1824
},
1925
"additionalProperties": false

src/griffe/docstrings/google.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,16 @@ def _read_returns_section(
459459
docstring: Docstring,
460460
*,
461461
offset: int,
462+
returns_multiple_items: bool,
462463
**options: Any, # noqa: ARG001
463464
) -> tuple[DocstringSectionReturns | None, int]:
464465
returns = []
465-
block, new_offset = _read_block_items(docstring, offset=offset)
466+
467+
if returns_multiple_items:
468+
block, new_offset = _read_block_items(docstring, offset=offset)
469+
else:
470+
one_block, new_offset = _read_block(docstring, offset=offset)
471+
block = [(new_offset, one_block.splitlines())]
466472

467473
for index, (line_number, return_lines) in enumerate(block):
468474
match = _RE_NAME_ANNOTATION_DESCRIPTION.match(return_lines[0])
@@ -731,6 +737,7 @@ def parse(
731737
*,
732738
ignore_init_summary: bool = False,
733739
trim_doctest_flags: bool = True,
740+
returns_multiple_items: bool = True,
734741
**options: Any,
735742
) -> list[DocstringSection]:
736743
"""Parse a docstring.
@@ -742,6 +749,7 @@ def parse(
742749
docstring: The docstring to parse.
743750
ignore_init_summary: Whether to ignore the summary in `__init__` methods' docstrings.
744751
trim_doctest_flags: Whether to remove doctest flags from Python example blocks.
752+
returns_multiple_items: Whether the `Returns` section has multiple items.
745753
**options: Additional parsing options.
746754
747755
Returns:
@@ -756,6 +764,7 @@ def parse(
756764
options = {
757765
"ignore_init_summary": ignore_init_summary,
758766
"trim_doctest_flags": trim_doctest_flags,
767+
"returns_multiple_items": returns_multiple_items,
759768
**options,
760769
}
761770

tests/test_docstrings/test_google.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import pytest
99

1010
from griffe.dataclasses import Attribute, Class, Docstring, Function, Module, Parameter, Parameters
11-
from griffe.docstrings.dataclasses import DocstringSectionKind
11+
from griffe.docstrings.dataclasses import DocstringReturn, DocstringSectionKind
1212
from griffe.docstrings.utils import parse_annotation
1313
from griffe.expressions import ExprName
1414

@@ -1359,3 +1359,74 @@ def test_single_line_with_trailing_whitespace(parse_google: ParserType) -> None:
13591359
assert len(sections) == 1
13601360
assert sections[0].kind is DocstringSectionKind.text
13611361
assert not warnings
1362+
1363+
1364+
@pytest.mark.parametrize(
1365+
("returns_multiple_items", "return_annotation", "expected"),
1366+
[
1367+
(
1368+
False,
1369+
None,
1370+
[DocstringReturn("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation=None)],
1371+
),
1372+
(
1373+
False,
1374+
"tuple[int, int]",
1375+
[DocstringReturn("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation="tuple[int, int]")],
1376+
),
1377+
(
1378+
True,
1379+
None,
1380+
[
1381+
DocstringReturn("", description="XXXXXXX\nYYYYYYY", annotation=None),
1382+
DocstringReturn("", description="ZZZZZZZ", annotation=None),
1383+
],
1384+
),
1385+
(
1386+
True,
1387+
"tuple[int,int]",
1388+
[
1389+
DocstringReturn("", description="XXXXXXX\nYYYYYYY", annotation="int"),
1390+
DocstringReturn("", description="ZZZZZZZ", annotation="int"),
1391+
],
1392+
),
1393+
],
1394+
)
1395+
def test_parse_returns_multiple_items(
1396+
parse_google: ParserType,
1397+
returns_multiple_items: bool,
1398+
return_annotation: str,
1399+
expected: list[DocstringReturn],
1400+
) -> None:
1401+
"""Parse Returns section with and without multiple items.
1402+
1403+
Parameters:
1404+
parse_google: Fixture parser.
1405+
returns_multiple_items: Whether the `Returns` section has multiple items.
1406+
return_annotation: The return annotation of the function to parse.
1407+
expected: The expected value of the parsed Returns section.
1408+
"""
1409+
parent = (
1410+
Function("func", returns=parse_annotation(return_annotation, Docstring("d", parent=Function("f"))))
1411+
if return_annotation is not None
1412+
else None
1413+
)
1414+
docstring = """
1415+
Returns:
1416+
XXXXXXX
1417+
YYYYYYY
1418+
ZZZZZZZ
1419+
"""
1420+
sections, _ = parse_google(
1421+
docstring,
1422+
returns_multiple_items=returns_multiple_items,
1423+
parent=parent,
1424+
)
1425+
1426+
assert len(sections) == 1
1427+
assert len(sections[0].value) == len(expected)
1428+
1429+
for annotated, expected_ in zip(sections[0].value, expected):
1430+
assert annotated.name == expected_.name
1431+
assert str(annotated.annotation) == str(expected_.annotation)
1432+
assert annotated.description == expected_.description

0 commit comments

Comments
 (0)