Skip to content

Commit cbb5079

Browse files
committed
fix: Keep newlines in parameter (and other multiline directives) descriptions in Sphinx docstrings
Issue-mkdocstrings-808: mkdocstrings/mkdocstrings#808
1 parent 30db8d7 commit cbb5079

2 files changed

Lines changed: 52 additions & 4 deletions

File tree

src/griffe/_internal/docstrings/sphinx.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from dataclasses import dataclass, field
1111
from typing import TYPE_CHECKING, Any, Callable, TypedDict
1212
from warnings import warn
13+
from inspect import cleandoc
1314

1415
from griffe._internal.docstrings.models import (
1516
DocstringAttribute,
@@ -466,10 +467,10 @@ def _consolidate_continuation_lines(lines: list[str], offset: int) -> tuple[str,
466467
# start processing after first item
467468
curr_line_index += 1
468469
while curr_line_index < len(lines) and not lines[curr_line_index].startswith(":"):
469-
block.append(lines[curr_line_index].lstrip())
470+
block.append(lines[curr_line_index])
470471
curr_line_index += 1
471472

472-
return " ".join(block).rstrip("\n"), curr_line_index - 1
473+
return cleandoc("\n".join(block)).rstrip("\n"), curr_line_index - 1
473474

474475

475476
def _consolidate_descriptive_type(descriptive_type: str) -> str:

tests/test_docstrings/test_sphinx.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def test_parse__param_field_multi_line__param_section(parse_sphinx: ParserType,
190190
assert len(sections) == 2
191191
assert sections[1].kind is DocstringSectionKind.parameters
192192
actual = sections[1].value[0]
193-
expected = DocstringParameter(SOME_NAME, description=f"{SOME_TEXT} {SOME_EXTRA_TEXT}")
193+
expected = DocstringParameter(SOME_NAME, description=f"{SOME_TEXT}\n{SOME_EXTRA_TEXT}")
194194
assert isinstance(actual, type(expected))
195195
assert actual.as_dict() == expected.as_dict()
196196

@@ -747,6 +747,53 @@ def test_parse__param_type_no_name__error_message(parse_sphinx: ParserType) -> N
747747
assert "Failed to get parameter name from" in warnings[0]
748748

749749

750+
def test_parse__param_multiline(parse_sphinx: ParserType) -> None:
751+
"""Parse multiline parameter descriptions.
752+
753+
Parameters:
754+
parse_sphinx: Fixture parser.
755+
"""
756+
docstring = """Do something.
757+
758+
:param foo: This is a docstring that is long enough to run onto a second line,
759+
because it is quite long.
760+
761+
A second paragraph is also required.
762+
:param bar: This is an example that is quite long, and also requires bullet
763+
points to be clear about intent:
764+
765+
* First thing
766+
767+
```
768+
a code block
769+
```
770+
771+
* Second thing
772+
* Third thing
773+
"""
774+
775+
sections, _ = parse_sphinx(docstring)
776+
param_section = sections[1]
777+
778+
param_foo = param_section.value[0]
779+
assert param_foo.description == (
780+
"This is a docstring that is long enough to run onto a second line,\n"
781+
"because it is quite long.\n\n"
782+
"A second paragraph is also required."
783+
)
784+
785+
param_bar = param_section.value[1]
786+
assert param_bar.description == (
787+
"This is an example that is quite long, and also requires bullet\n"
788+
"points to be clear about intent:\n\n"
789+
"* First thing\n\n"
790+
" ```\n"
791+
" a code block\n"
792+
" ```\n\n"
793+
"* Second thing\n"
794+
"* Third thing"
795+
)
796+
750797
@pytest.mark.parametrize(
751798
"docstring",
752799
[
@@ -775,7 +822,7 @@ def test_parse__attribute_field_multi_line__param_section(parse_sphinx: ParserTy
775822
assert len(sections) == 2
776823
assert sections[1].kind is DocstringSectionKind.attributes
777824
actual = sections[1].value[0]
778-
expected = DocstringAttribute(SOME_NAME, description=f"{SOME_TEXT} {SOME_EXTRA_TEXT}")
825+
expected = DocstringAttribute(SOME_NAME, description=f"{SOME_TEXT}\n{SOME_EXTRA_TEXT}")
779826
assert isinstance(actual, type(expected))
780827
assert actual.as_dict() == expected.as_dict()
781828
assert not warnings

0 commit comments

Comments
 (0)