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 numpy block linebreaks #168

Merged
merged 9 commits into from
Jun 21, 2023
66 changes: 44 additions & 22 deletions src/griffe/docstrings/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ def _is_dash_line(line: str) -> bool:
return not _is_empty_line(line) and _is_empty_line(line.replace("-", ""))


def _read_block_items(docstring: Docstring, *, offset: int) -> tuple[list[list[str]], int]:
def _read_block_items(
docstring: Docstring,
*,
offset: int,
allow_block_breaks:bool,
**options: Any, # noqa: ARG001
) -> tuple[list[list[str]], int]:
lines = docstring.lines
if offset >= len(lines):
return [], offset
Expand Down Expand Up @@ -145,14 +151,24 @@ def _read_block_items(docstring: Docstring, *, offset: int) -> tuple[list[list[s
previous_was_empty = False

elif _is_empty_line(line):
# two line breaks indicate the start of a new section
if previous_was_empty:
break

# empty line: preserve it in the current item
current_item.append("")
previous_was_empty = True

else:
if previous_was_empty:
# preserve original behavior, that a single line break between block
# items triggers a new section
if not allow_block_breaks and previous_was_empty:
break
# new item

# detect the start of a new section
if new_offset+1 < len(lines) and lines[new_offset+1].startswith("---"):
break

items.append(current_item)
current_item = [line]
previous_was_empty = False
Expand Down Expand Up @@ -226,11 +242,12 @@ def _read_parameters(
*,
offset: int,
warn_unknown_params: bool = True,
**options: Any,
) -> tuple[list[DocstringParameter], int]:
parameters = []
annotation: str | Name | Expression | None

items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

for item in items:
match = _RE_PARAMETER.match(item[0])
Expand Down Expand Up @@ -288,9 +305,9 @@ def _read_parameters_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionParameters | None, int]:
parameters, new_offset = _read_parameters(docstring, offset=offset)
parameters, new_offset = _read_parameters(docstring, offset=offset, **options)

if parameters:
return DocstringSectionParameters(parameters), new_offset
Expand All @@ -303,9 +320,9 @@ def _read_other_parameters_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionOtherParameters | None, int]:
parameters, new_offset = _read_parameters(docstring, offset=offset, warn_unknown_params=False)
parameters, new_offset = _read_parameters(docstring, offset=offset, warn_unknown_params=False, **options)

if parameters:
return DocstringSectionOtherParameters(parameters), new_offset
Expand All @@ -318,12 +335,12 @@ def _read_deprecated_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionDeprecated | None, int]:
# deprecated
# SINCE_VERSION
# TEXT?
items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

if not items:
_warn(docstring, new_offset, f"Empty deprecated section at line {offset}")
Expand All @@ -342,11 +359,11 @@ def _read_returns_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionReturns | None, int]:
# (NAME : )?TYPE
# TEXT?
items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

if not items:
_warn(docstring, new_offset, f"Empty returns section at line {offset}")
Expand Down Expand Up @@ -397,12 +414,12 @@ def _read_yields_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionYields | None, int]:
# yields
# (NAME : )?TYPE
# TEXT?
items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

if not items:
_warn(docstring, new_offset, f"Empty yields section at line {offset}")
Expand Down Expand Up @@ -445,12 +462,12 @@ def _read_receives_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionReceives | None, int]:
# receives
# (NAME : )?TYPE
# TEXT?
items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

if not items:
_warn(docstring, new_offset, f"Empty receives section at line {offset}")
Expand Down Expand Up @@ -488,12 +505,12 @@ def _read_raises_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionRaises | None, int]:
# raises
# EXCEPTION
# TEXT?
items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

if not items:
_warn(docstring, new_offset, f"Empty raises section at line {offset}")
Expand All @@ -511,12 +528,12 @@ def _read_warns_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionWarns | None, int]:
# warns
# WARNING
# TEXT?
items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

if not items:
_warn(docstring, new_offset, f"Empty warns section at line {offset}")
Expand All @@ -534,12 +551,12 @@ def _read_attributes_section(
docstring: Docstring,
*,
offset: int,
**options: Any, # noqa: ARG001
**options: Any,
) -> tuple[DocstringSectionAttributes | None, int]:
# attributes (for classes)
# NAME( : TYPE)?
# TEXT?
items, new_offset = _read_block_items(docstring, offset=offset)
items, new_offset = _read_block_items(docstring, offset=offset, **options)

if not items:
_warn(docstring, new_offset, f"Empty attributes section at line {offset}")
Expand Down Expand Up @@ -648,6 +665,7 @@ def parse(
*,
ignore_init_summary: bool = False,
trim_doctest_flags: bool = True,
allow_block_breaks: bool = False,
pawamoy marked this conversation as resolved.
Show resolved Hide resolved
**options: Any,
) -> list[DocstringSection]:
"""Parse a docstring.
Expand All @@ -659,6 +677,9 @@ 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.
allow_block_breaks: Whether to consider an empty line between items in a section
with a formatted block, like Parameters or Returns, to be the end of the section.
If False, you can create a section using two empty lines.
**options: Additional parsing options.

Returns:
Expand All @@ -673,6 +694,7 @@ def parse(
options = {
"trim_doctest_flags": trim_doctest_flags,
"ignore_init_summary": ignore_init_summary,
"allow_block_breaks": allow_block_breaks,
**options,
}

Expand Down
7 changes: 7 additions & 0 deletions tests/test_docstrings/test_numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ def test_empty_indented_lines_in_section_with_items(parse_numpy: ParserType) ->
assert len(sections[0].value) == 1


# allow_block_breaks requires at least 2 newlines to create a new section
sections2, _ = parse_numpy(docstring, allow_block_breaks = True)
assert len(sections2) == 1
assert len(sections2[0].value) == 2



# =============================================================================================
# Annotations
def test_prefer_docstring_type_over_annotation(parse_numpy: ParserType) -> None:
Expand Down