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

Commit

Permalink
Merge branch 'master' into sections
Browse files Browse the repository at this point in the history
  • Loading branch information
sambhav authored Dec 30, 2021
2 parents 88c788e + 1011866 commit 01ce65b
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 16 deletions.
2 changes: 2 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ Current Development Version

New Features

* Allow for hanging indent when documenting args in Google style. (#449)
* Add support for `property_decorators` config to ignore D401.
* Add support for Python 3.10 (#554).
* No longer emit D401 for sections at the start of docstrings (#556).
* Replace D10X errors with D419 if docstring exists but is empty (#559).

6.1.1 - May 17th, 2021
---------------------------
Expand Down
54 changes: 46 additions & 8 deletions src/pydocstyle/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from collections import namedtuple
from itertools import chain, takewhile
from re import compile as re
from textwrap import dedent

from . import violations
from .config import IllegalConfiguration
Expand Down Expand Up @@ -122,6 +123,8 @@ class ConventionChecker:
r"\s*"
# Followed by a colon
r":"
# Might have a new line and leading whitespace
r"\n?\s*"
# Followed by 1 or more characters - which is the docstring for the parameter
".+"
)
Expand Down Expand Up @@ -196,12 +199,7 @@ def check_docstring_missing(self, definition, docstring):
with a single underscore.
"""
if (
not docstring
and definition.is_public
or docstring
and is_blank(ast.literal_eval(docstring))
):
if not docstring and definition.is_public:
codes = {
Module: violations.D100,
Class: violations.D101,
Expand All @@ -227,6 +225,18 @@ def check_docstring_missing(self, definition, docstring):
}
return codes[type(definition)]()

@check_for(Definition, terminal=True)
def check_docstring_empty(self, definition, docstring):
"""D419: Docstring is empty.
If the user provided a docstring but it was empty, it is like they never provided one.
NOTE: This used to report as D10X errors.
"""
if docstring and is_blank(ast.literal_eval(docstring)):
return violations.D419()

@check_for(Definition)
def check_one_liners(self, definition, docstring):
"""D200: One-liner docstrings should fit on one line with quotes.
Expand Down Expand Up @@ -854,10 +864,38 @@ def _check_args_section(docstring, definition, context):
* The section documents all function arguments (D417)
except `self` or `cls` if it is a method.
Documentation for each arg should start at the same indentation
level. For example, in this case x and y are distinguishable::
Args:
x: Lorem ipsum dolor sit amet
y: Ut enim ad minim veniam
In the case below, we only recognize x as a documented parameter
because the rest of the content is indented as if it belongs
to the description for x::
Args:
x: Lorem ipsum dolor sit amet
y: Ut enim ad minim veniam
"""
docstring_args = set()
for line in context.following_lines:
match = ConventionChecker.GOOGLE_ARGS_REGEX.match(line)
# normalize leading whitespace
args_content = dedent("\n".join(context.following_lines)).strip()

args_sections = []
for line in args_content.splitlines(keepends=True):
if not line[:1].isspace():
# This line is the start of documentation for the next
# parameter because it doesn't start with any whitespace.
args_sections.append(line)
else:
# This is a continuation of documentation for the last
# parameter because it does start with whitespace.
args_sections[-1] += line

for section in args_sections:
match = ConventionChecker.GOOGLE_ARGS_REGEX.match(section)
if match:
docstring_args.add(match.group(1))
yield from ConventionChecker._check_missing_args(
Expand Down
4 changes: 4 additions & 0 deletions src/pydocstyle/violations.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,10 @@ def to_rst(cls) -> str:
'D418',
'Function/ Method decorated with @overload shouldn\'t contain a docstring',
)
D419 = D4xx.create_error(
'D419',
'Docstring is empty',
)


class AttrDict(dict):
Expand Down
2 changes: 1 addition & 1 deletion src/tests/test_cases/capitalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def not_capitalized():


# Make sure empty docstrings don't generate capitalization errors.
@expect("D103: Missing docstring in public function")
@expect("D419: Docstring is empty")
def empty_docstring():
""""""

Expand Down
5 changes: 1 addition & 4 deletions src/tests/test_cases/sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,7 @@ def test_missing_docstring(a, b): # noqa: D213, D407
"""

@staticmethod
@expect("D417: Missing argument descriptions in the docstring "
"(argument(s) skip, verbose are missing descriptions in "
"'test_missing_docstring_another' docstring)", arg_count=2)
def test_missing_docstring_another(skip, verbose): # noqa: D213, D407
def test_hanging_indent(skip, verbose): # noqa: D213, D407
"""Do stuff.
Args:
Expand Down
6 changes: 3 additions & 3 deletions src/tests/test_cases/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

class class_:

expect('meta', 'D106: Missing docstring in public nested class')
expect('meta', 'D419: Docstring is empty')

class meta:
""""""
Expand Down Expand Up @@ -64,13 +64,13 @@ def __call__(self=None, x=None, y=None, z=None):
pass


@expect('D103: Missing docstring in public function')
@expect('D419: Docstring is empty')
def function():
""" """
def ok_since_nested():
pass

@expect('D103: Missing docstring in public function')
@expect('D419: Docstring is empty')
def nested():
''

Expand Down

0 comments on commit 01ce65b

Please sign in to comment.