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

Fix false-positive D405 recognition #317

Merged
merged 8 commits into from Jun 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/release_notes.rst
Expand Up @@ -17,6 +17,11 @@ New features
line of the ``def``/``class`` it corresponds to (#238, #83).
* Updated description of pep257 and numpy conventions (#300).

Bug Fixes

* Fixed a false-positive recognition of section names causing D405 to be
reported (#311, #317).


2.1.1 - October 9th, 2017
-------------------------
Expand Down
37 changes: 26 additions & 11 deletions src/pydocstyle/checker.py
Expand Up @@ -436,7 +436,7 @@ def _get_leading_words(line):

For example, if `line` is " Hello world!!!", returns "Hello world".
"""
result = re("[A-Za-z ]+").match(line.strip())
result = re("[\w ]+").match(line.strip())
if result is not None:
return result.group()

Expand All @@ -454,30 +454,45 @@ def _is_a_docstring_section(context):

This is another line in the docstring. It describes stuff,
but we forgot to add a blank line between it and the section name.
Returns <----- A real section name. The previous line ends with
------- a period, therefore it is in a new
Parameters <-- A real section name. The previous line ends with
---------- a period, therefore it is in a new
grammatical context.
param : int
examples : list <------- Not a section - previous line doesn't end
A list of examples. with punctuation.
notes : list <---------- Not a section - there's text after the
A list of notes. colon.

Notes: <--- Suspected as a context because there's a suffix to the
----- section, but it's a colon so it's probably a mistake.
Bla.

'''

To make sure this is really a section we check these conditions:
* There's no suffix to the section name.
* The previous line ends with punctuation.
* The previous line is empty.
* There's no suffix to the section name or it's just a colon AND
* The previous line is empty OR it ends with punctuation.

If one of the conditions is true, we will consider the line as
a section name.
"""
section_name_suffix = context.line.lstrip(context.section_name).strip()
section_name_suffix = \
context.line.strip().lstrip(context.section_name.strip()).strip()

section_suffix_is_only_colon = section_name_suffix == ':'

punctuation = [',', ';', '.', '-', '\\', '/', ']', '}', ')']
prev_line_ends_with_punctuation = \
any(context.previous_line.strip().endswith(x) for x in punctuation)

return (is_blank(section_name_suffix) or
prev_line_ends_with_punctuation or
is_blank(context.previous_line))
this_line_looks_like_a_section_name = \
is_blank(section_name_suffix) or section_suffix_is_only_colon

prev_line_looks_like_end_of_paragraph = \
prev_line_ends_with_punctuation or is_blank(context.previous_line)

return (this_line_looks_like_a_section_name and
prev_line_looks_like_end_of_paragraph)

@classmethod
def _check_section_underline(cls, section_name, context, indentation):
Expand Down Expand Up @@ -625,7 +640,7 @@ def _suspected_as_section(_line):
'is_last_section'))

# First - create a list of possible contexts. Note that the
# `following_linex` member is until the end of the docstring.
# `following_lines` member is until the end of the docstring.
contexts = (SectionContext(self._get_leading_words(lines[i].strip()),
lines[i - 1],
lines[i],
Expand Down
25 changes: 25 additions & 0 deletions src/tests/test_cases/sections.py
Expand Up @@ -215,3 +215,28 @@ def multiple_sections():
My attention.

"""


@expect(_D213)
def false_positive_section_prefix():
"""Toggle the gizmo.

Parameters
----------
attributes_are_fun: attributes for the function.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps also add a case where the parameter name is exactly a section header name (e.g., attributes)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at the test below it - it's exactly that.


"""


@expect(_D213)
def section_names_as_parameter_names():
"""Toggle the gizmo.

Parameters
----------
notes : list
A list of wonderful notes.
examples: list
A list of horrible examples.

"""
3 changes: 2 additions & 1 deletion tox.ini
Expand Up @@ -11,7 +11,8 @@ envlist = {py27, py34, py35, py36, pypy}-{tests, install}, docs
setenv =
LANG=C
LC_ALL=C
commands = py.test --pep8 --cache-clear -vv src/tests
# To pass arguments to py.test, use `tox [options] -- [pytest posargs]`.
commands = py.test --pep8 --cache-clear -vv src/tests {posargs}
deps =
-rrequirements/runtime.txt
-rrequirements/tests.txt
Expand Down