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

Commit 09b23a1

Browse files
authored
Merge branch 'master' into fix-match
2 parents 1ec7c45 + 1011866 commit 09b23a1

File tree

8 files changed

+62
-19
lines changed

8 files changed

+62
-19
lines changed

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
strategy:
99
matrix:
1010
os: [macos-latest, ubuntu-latest, windows-latest]
11-
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
11+
python-version: ["3.7", "3.8", "3.9", "3.10"]
1212

1313
steps:
1414
- uses: actions/checkout@v2

docs/release_notes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ Current Development Version
1010

1111
New Features
1212

13+
* Allow for hanging indent when documenting args in Google style. (#449)
1314
* Add support for `property_decorators` config to ignore D401.
1415
* Add support for Python 3.10 (#554).
16+
* Replace D10X errors with D419 if docstring exists but is empty (#559).
1517

1618
Bug Fixes
1719

requirements/tests.txt

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
pytest==6.2.5
2-
mypy==0.782
3-
black==20.8b1
2+
mypy==0.930
3+
black==21.12b0
44
isort==5.4.2
5+
types-toml
6+
types-setuptools

src/pydocstyle/checker.py

+46-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from collections import namedtuple
77
from itertools import chain, takewhile
88
from re import compile as re
9+
from textwrap import dedent
910

1011
from . import violations
1112
from .config import IllegalConfiguration
@@ -122,6 +123,8 @@ class ConventionChecker:
122123
r"\s*"
123124
# Followed by a colon
124125
r":"
126+
# Might have a new line and leading whitespace
127+
r"\n?\s*"
125128
# Followed by 1 or more characters - which is the docstring for the parameter
126129
".+"
127130
)
@@ -196,12 +199,7 @@ def check_docstring_missing(self, definition, docstring):
196199
with a single underscore.
197200
198201
"""
199-
if (
200-
not docstring
201-
and definition.is_public
202-
or docstring
203-
and is_blank(ast.literal_eval(docstring))
204-
):
202+
if not docstring and definition.is_public:
205203
codes = {
206204
Module: violations.D100,
207205
Class: violations.D101,
@@ -227,6 +225,18 @@ def check_docstring_missing(self, definition, docstring):
227225
}
228226
return codes[type(definition)]()
229227

228+
@check_for(Definition, terminal=True)
229+
def check_docstring_empty(self, definition, docstring):
230+
"""D419: Docstring is empty.
231+
232+
If the user provided a docstring but it was empty, it is like they never provided one.
233+
234+
NOTE: This used to report as D10X errors.
235+
236+
"""
237+
if docstring and is_blank(ast.literal_eval(docstring)):
238+
return violations.D419()
239+
230240
@check_for(Definition)
231241
def check_one_liners(self, definition, docstring):
232242
"""D200: One-liner docstrings should fit on one line with quotes.
@@ -836,10 +846,38 @@ def _check_args_section(docstring, definition, context):
836846
* The section documents all function arguments (D417)
837847
except `self` or `cls` if it is a method.
838848
849+
Documentation for each arg should start at the same indentation
850+
level. For example, in this case x and y are distinguishable::
851+
852+
Args:
853+
x: Lorem ipsum dolor sit amet
854+
y: Ut enim ad minim veniam
855+
856+
In the case below, we only recognize x as a documented parameter
857+
because the rest of the content is indented as if it belongs
858+
to the description for x::
859+
860+
Args:
861+
x: Lorem ipsum dolor sit amet
862+
y: Ut enim ad minim veniam
839863
"""
840864
docstring_args = set()
841-
for line in context.following_lines:
842-
match = ConventionChecker.GOOGLE_ARGS_REGEX.match(line)
865+
# normalize leading whitespace
866+
args_content = dedent("\n".join(context.following_lines)).strip()
867+
868+
args_sections = []
869+
for line in args_content.splitlines(keepends=True):
870+
if not line[:1].isspace():
871+
# This line is the start of documentation for the next
872+
# parameter because it doesn't start with any whitespace.
873+
args_sections.append(line)
874+
else:
875+
# This is a continuation of documentation for the last
876+
# parameter because it does start with whitespace.
877+
args_sections[-1] += line
878+
879+
for section in args_sections:
880+
match = ConventionChecker.GOOGLE_ARGS_REGEX.match(section)
843881
if match:
844882
docstring_args.add(match.group(1))
845883
yield from ConventionChecker._check_missing_args(

src/pydocstyle/violations.py

+4
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ def to_rst(cls) -> str:
415415
'D418',
416416
'Function/ Method decorated with @overload shouldn\'t contain a docstring',
417417
)
418+
D419 = D4xx.create_error(
419+
'D419',
420+
'Docstring is empty',
421+
)
418422

419423

420424
class AttrDict(dict):

src/tests/test_cases/capitalization.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def not_capitalized():
1313

1414

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

src/tests/test_cases/sections.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,7 @@ def test_missing_docstring(a, b): # noqa: D213, D407
367367
"""
368368

369369
@staticmethod
370-
@expect("D417: Missing argument descriptions in the docstring "
371-
"(argument(s) skip, verbose are missing descriptions in "
372-
"'test_missing_docstring_another' docstring)", arg_count=2)
373-
def test_missing_docstring_another(skip, verbose): # noqa: D213, D407
370+
def test_hanging_indent(skip, verbose): # noqa: D213, D407
374371
"""Do stuff.
375372
376373
Args:

src/tests/test_cases/test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
class class_:
1515

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

1818
class meta:
1919
""""""
@@ -64,13 +64,13 @@ def __call__(self=None, x=None, y=None, z=None):
6464
pass
6565

6666

67-
@expect('D103: Missing docstring in public function')
67+
@expect('D419: Docstring is empty')
6868
def function():
6969
""" """
7070
def ok_since_nested():
7171
pass
7272

73-
@expect('D103: Missing docstring in public function')
73+
@expect('D419: Docstring is empty')
7474
def nested():
7575
''
7676

0 commit comments

Comments
 (0)