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

Commit 8780cc1

Browse files
committed
Skip D401 for docstrings that start directly with a section.
1 parent c8e81d6 commit 8780cc1

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

docs/release_notes.rst

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ New Features
1212

1313
* Add support for `property_decorators` config to ignore D401.
1414
* Add support for Python 3.10 (#554).
15+
* No longer emit D401 for sections at the start of docstrings (#556).
1516

1617
6.1.1 - May 17th, 2021
1718
---------------------------

src/pydocstyle/checker.py

+28-5
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,9 @@ def check_imperative_mood(self, function, docstring): # def context
504504
"Returns the pathname ...".
505505
506506
"""
507+
ctxs = list(self._get_section_contexts_autodetect(docstring))
508+
if ctxs and ctxs[0].is_docstring_start:
509+
return
507510
if (
508511
docstring
509512
and not function.is_test
@@ -587,6 +590,16 @@ def check_starts_with_this(self, function, docstring):
587590
if first_word.lower() == 'this':
588591
return violations.D404()
589592

593+
@staticmethod
594+
def _is_at_docstring_start(context):
595+
"""Return whether a `SectionContext` occurs at the start of a docstring."""
596+
return context.original_index == 1 and context.previous_line in [
597+
'"',
598+
"'",
599+
'"""',
600+
"'''",
601+
]
602+
590603
@staticmethod
591604
def _is_docstring_section(context):
592605
"""Check if the suspected context is really a section header.
@@ -639,7 +652,9 @@ def _is_docstring_section(context):
639652
)
640653

641654
prev_line_looks_like_end_of_paragraph = (
642-
prev_line_ends_with_punctuation or is_blank(context.previous_line)
655+
prev_line_ends_with_punctuation
656+
or is_blank(context.previous_line)
657+
or context.is_docstring_start
643658
)
644659

645660
return (
@@ -749,7 +764,10 @@ def _check_common_section(
749764
else:
750765
yield violations.D410(capitalized_section)
751766

752-
if not is_blank(context.previous_line):
767+
if (
768+
not is_blank(context.previous_line)
769+
and not context.is_docstring_start
770+
):
753771
yield violations.D411(capitalized_section)
754772

755773
yield from cls._check_blanks_and_section_underline(
@@ -945,6 +963,7 @@ def _suspected_as_section(_line):
945963
'line',
946964
'following_lines',
947965
'original_index',
966+
'is_docstring_start',
948967
'is_last_section',
949968
),
950969
)
@@ -960,15 +979,18 @@ def _suspected_as_section(_line):
960979
lines[i + 1 :],
961980
i,
962981
False,
982+
False,
963983
)
964984
for i in suspected_section_indices
965985
)
966-
967-
# Now that we have manageable objects - rule out false positives.
968986
contexts = (
969-
c for c in contexts if ConventionChecker._is_docstring_section(c)
987+
c._replace(is_docstring_start=cls._is_at_docstring_start(c))
988+
for c in contexts
970989
)
971990

991+
# Now that we have manageable objects - rule out false positives.
992+
contexts = (c for c in contexts if cls._is_docstring_section(c))
993+
972994
# Now we shall trim the `following lines` field to only reach the
973995
# next section name.
974996
for a, b in pairwise(contexts, None):
@@ -980,6 +1002,7 @@ def _suspected_as_section(_line):
9801002
a.line,
9811003
lines[a.original_index + 1 : end],
9821004
a.original_index,
1005+
a.is_docstring_start,
9831006
b is None,
9841007
)
9851008

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)