diff --git a/packages/griffelib/src/griffe/_internal/docstrings/numpy.py b/packages/griffelib/src/griffe/_internal/docstrings/numpy.py index ba2e2e44..638f35b2 100644 --- a/packages/griffelib/src/griffe/_internal/docstrings/numpy.py +++ b/packages/griffelib/src/griffe/_internal/docstrings/numpy.py @@ -816,6 +816,7 @@ def _read_examples_section( current_text.append(line) elif in_code_example: + line = line.lstrip() # noqa: PLW2901 if trim_doctest_flags: line = _RE_DOCTEST_FLAGS.sub("", line) # noqa: PLW2901 line = _RE_DOCTEST_BLANKLINE.sub("", line) # noqa: PLW2901 @@ -828,15 +829,15 @@ def _read_examples_section( elif in_code_block: current_text.append(line) - elif line.startswith(">>>"): + elif (lstripped := line.lstrip()).startswith(">>>"): if current_text: sub_sections.append((DocstringSectionKind.text, "\n".join(current_text).rstrip("\n"))) current_text = [] in_code_example = True if trim_doctest_flags: - line = _RE_DOCTEST_FLAGS.sub("", line) # noqa: PLW2901 - current_example.append(line) + lstripped = _RE_DOCTEST_FLAGS.sub("", lstripped) + current_example.append(lstripped) else: current_text.append(line) diff --git a/packages/griffelib/tests/test_docstrings/test_numpy.py b/packages/griffelib/tests/test_docstrings/test_numpy.py index 344856e5..550fc63e 100644 --- a/packages/griffelib/tests/test_docstrings/test_numpy.py +++ b/packages/griffelib/tests/test_docstrings/test_numpy.py @@ -786,6 +786,39 @@ def test_examples_section(parse_numpy: ParserType) -> None: assert examples.value[3][1].startswith(">>> a = 0 # doctest: +SKIP") +def test_indented_examples_section(parse_numpy: ParserType) -> None: + """Parse examples of differing indentation levels. + + Authors might indent ``>>>`` lines as a way of highlighting code + examples. The parser should be able to handle these cases correctly. + + Parameters: + parse_numpy: Fixture parser. + """ + # NOTE in this example that only the first example is indented. + # Both examples should still be parsed + docstring = """ + Examples + -------- + Create an object: + >>> obj = MyClass() + >>> obj.method() + + Chain multiple calls: + >>> result = ( + ... MyClass() + ... .method() + ... ) + """ + + sections, _ = parse_numpy(docstring) + assert len(sections) == 1 + examples = [v[1] for v in sections[0].value if v[0] is DocstringSectionKind.examples] + assert len(examples) == 2 + assert examples[0] == ">>> obj = MyClass()\n>>> obj.method()" + assert examples[1] == ">>> result = (\n... MyClass()\n... .method()\n... )" + + def test_examples_section_when_followed_by_named_section(parse_numpy: ParserType) -> None: """Parse examples section followed by another section.