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

Commit 9f7da94

Browse files
committed
Skip D401 for docstrings that start directly with a section.
1 parent 74ca377 commit 9f7da94

File tree

3 files changed

+51
-5
lines changed

3 files changed

+51
-5
lines changed

docs/release_notes.rst

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Release Notes
44
**pydocstyle** version numbers follow the
55
`Semantic Versioning <http://semver.org/>`_ specification.
66

7+
next
8+
----
9+
10+
Bug Fixes
11+
12+
* No longer emit D401 for sections at the start of docstrings (#556).
13+
714
6.3.0 - January 17th, 2023
815
--------------------------
916

src/pydocstyle/checker.py

+28-5
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,9 @@ def check_imperative_mood(self, function, docstring): # def context
521521
"Returns the pathname ...".
522522
523523
"""
524+
ctxs = list(self._get_section_contexts_autodetect(docstring))
525+
if ctxs and ctxs[0].is_docstring_start:
526+
return
524527
if (
525528
docstring
526529
and not function.is_test
@@ -604,6 +607,16 @@ def check_starts_with_this(self, function, docstring):
604607
if first_word.lower() == 'this':
605608
return violations.D404()
606609

610+
@staticmethod
611+
def _is_at_docstring_start(context):
612+
"""Return whether a `SectionContext` occurs at the start of a docstring."""
613+
return context.original_index == 1 and context.previous_line in [
614+
'"',
615+
"'",
616+
'"""',
617+
"'''",
618+
]
619+
607620
@staticmethod
608621
def _is_docstring_section(context):
609622
"""Check if the suspected context is really a section header.
@@ -656,7 +669,9 @@ def _is_docstring_section(context):
656669
)
657670

658671
prev_line_looks_like_end_of_paragraph = (
659-
prev_line_ends_with_punctuation or is_blank(context.previous_line)
672+
prev_line_ends_with_punctuation
673+
or is_blank(context.previous_line)
674+
or context.is_docstring_start
660675
)
661676

662677
return (
@@ -766,7 +781,10 @@ def _check_common_section(
766781
else:
767782
yield violations.D410(capitalized_section)
768783

769-
if not is_blank(context.previous_line):
784+
if (
785+
not is_blank(context.previous_line)
786+
and not context.is_docstring_start
787+
):
770788
yield violations.D411(capitalized_section)
771789

772790
yield from cls._check_blanks_and_section_underline(
@@ -1004,6 +1022,7 @@ def _suspected_as_section(_line):
10041022
'line',
10051023
'following_lines',
10061024
'original_index',
1025+
'is_docstring_start',
10071026
'is_last_section',
10081027
),
10091028
)
@@ -1019,15 +1038,18 @@ def _suspected_as_section(_line):
10191038
lines[i + 1 :],
10201039
i,
10211040
False,
1041+
False,
10221042
)
10231043
for i in suspected_section_indices
10241044
)
1025-
1026-
# Now that we have manageable objects - rule out false positives.
10271045
contexts = (
1028-
c for c in contexts if ConventionChecker._is_docstring_section(c)
1046+
c._replace(is_docstring_start=cls._is_at_docstring_start(c))
1047+
for c in contexts
10291048
)
10301049

1050+
# Now that we have manageable objects - rule out false positives.
1051+
contexts = (c for c in contexts if cls._is_docstring_section(c))
1052+
10311053
# Now we shall trim the `following lines` field to only reach the
10321054
# next section name.
10331055
for a, b in pairwise(contexts, None):
@@ -1039,6 +1061,7 @@ def _suspected_as_section(_line):
10391061
a.line,
10401062
lines[a.original_index + 1 : end],
10411063
a.original_index,
1064+
a.is_docstring_start,
10421065
b is None,
10431066
)
10441067

src/tests/test_cases/sections.py

+16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
expect = expectation.expect
77

88

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

@@ -191,6 +192,21 @@ def section_name_in_first_line(): # noqa: D416
191192
"""
192193

193194

195+
@expect(_D212)
196+
@expect("D400: First line should end with a period (not 's')")
197+
@expect("D415: First line should end with a period, question "
198+
"mark, or exclamation point (not 's')")
199+
@expect("D205: 1 blank line required between summary line and description "
200+
"(found 0)")
201+
def section_name_in_first_nonblank_line(): # noqa: D416
202+
"""
203+
Returns
204+
-------
205+
A value of some sort.
206+
207+
"""
208+
209+
194210
@expect(_D213)
195211
@expect("D405: Section name should be properly capitalized "
196212
"('Short Summary', not 'Short summary')")

0 commit comments

Comments
 (0)