Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
Skip D401 for docstrings that start directly with a section.
Browse files Browse the repository at this point in the history
  • Loading branch information
anntzer committed Aug 28, 2023
1 parent 74ca377 commit 9f7da94
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 5 deletions.
7 changes: 7 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Release Notes
**pydocstyle** version numbers follow the
`Semantic Versioning <http://semver.org/>`_ specification.

next
----

Bug Fixes

* No longer emit D401 for sections at the start of docstrings (#556).

6.3.0 - January 17th, 2023
--------------------------

Expand Down
33 changes: 28 additions & 5 deletions src/pydocstyle/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,9 @@ def check_imperative_mood(self, function, docstring): # def context
"Returns the pathname ...".
"""
ctxs = list(self._get_section_contexts_autodetect(docstring))
if ctxs and ctxs[0].is_docstring_start:
return
if (
docstring
and not function.is_test
Expand Down Expand Up @@ -604,6 +607,16 @@ def check_starts_with_this(self, function, docstring):
if first_word.lower() == 'this':
return violations.D404()

@staticmethod
def _is_at_docstring_start(context):
"""Return whether a `SectionContext` occurs at the start of a docstring."""
return context.original_index == 1 and context.previous_line in [
'"',
"'",
'"""',
"'''",
]

@staticmethod
def _is_docstring_section(context):
"""Check if the suspected context is really a section header.
Expand Down Expand Up @@ -656,7 +669,9 @@ def _is_docstring_section(context):
)

prev_line_looks_like_end_of_paragraph = (
prev_line_ends_with_punctuation or is_blank(context.previous_line)
prev_line_ends_with_punctuation
or is_blank(context.previous_line)
or context.is_docstring_start
)

return (
Expand Down Expand Up @@ -766,7 +781,10 @@ def _check_common_section(
else:
yield violations.D410(capitalized_section)

if not is_blank(context.previous_line):
if (
not is_blank(context.previous_line)
and not context.is_docstring_start
):
yield violations.D411(capitalized_section)

yield from cls._check_blanks_and_section_underline(
Expand Down Expand Up @@ -1004,6 +1022,7 @@ def _suspected_as_section(_line):
'line',
'following_lines',
'original_index',
'is_docstring_start',
'is_last_section',
),
)
Expand All @@ -1019,15 +1038,18 @@ def _suspected_as_section(_line):
lines[i + 1 :],
i,
False,
False,
)
for i in suspected_section_indices
)

# Now that we have manageable objects - rule out false positives.
contexts = (
c for c in contexts if ConventionChecker._is_docstring_section(c)
c._replace(is_docstring_start=cls._is_at_docstring_start(c))
for c in contexts
)

# Now that we have manageable objects - rule out false positives.
contexts = (c for c in contexts if cls._is_docstring_section(c))

# Now we shall trim the `following lines` field to only reach the
# next section name.
for a, b in pairwise(contexts, None):
Expand All @@ -1039,6 +1061,7 @@ def _suspected_as_section(_line):
a.line,
lines[a.original_index + 1 : end],
a.original_index,
a.is_docstring_start,
b is None,
)

Expand Down
16 changes: 16 additions & 0 deletions src/tests/test_cases/sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
expect = expectation.expect


_D212 = 'D212: Multi-line docstring summary should start at the first line'
_D213 = 'D213: Multi-line docstring summary should start at the second line'
_D400 = "D400: First line should end with a period (not '!')"

Expand Down Expand Up @@ -191,6 +192,21 @@ def section_name_in_first_line(): # noqa: D416
"""


@expect(_D212)
@expect("D400: First line should end with a period (not 's')")
@expect("D415: First line should end with a period, question "
"mark, or exclamation point (not 's')")
@expect("D205: 1 blank line required between summary line and description "
"(found 0)")
def section_name_in_first_nonblank_line(): # noqa: D416
"""
Returns
-------
A value of some sort.
"""


@expect(_D213)
@expect("D405: Section name should be properly capitalized "
"('Short Summary', not 'Short summary')")
Expand Down

0 comments on commit 9f7da94

Please sign in to comment.