6
6
from collections import namedtuple
7
7
from itertools import chain , takewhile
8
8
from re import compile as re
9
+ from textwrap import dedent
9
10
10
11
from . import violations
11
12
from .config import IllegalConfiguration
@@ -122,6 +123,8 @@ class ConventionChecker:
122
123
r"\s*"
123
124
# Followed by a colon
124
125
r":"
126
+ # Might have a new line and leading whitespace
127
+ r"\n?\s*"
125
128
# Followed by 1 or more characters - which is the docstring for the parameter
126
129
".+"
127
130
)
@@ -196,12 +199,7 @@ def check_docstring_missing(self, definition, docstring):
196
199
with a single underscore.
197
200
198
201
"""
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 :
205
203
codes = {
206
204
Module : violations .D100 ,
207
205
Class : violations .D101 ,
@@ -227,6 +225,18 @@ def check_docstring_missing(self, definition, docstring):
227
225
}
228
226
return codes [type (definition )]()
229
227
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
+
230
240
@check_for (Definition )
231
241
def check_one_liners (self , definition , docstring ):
232
242
"""D200: One-liner docstrings should fit on one line with quotes.
@@ -836,10 +846,38 @@ def _check_args_section(docstring, definition, context):
836
846
* The section documents all function arguments (D417)
837
847
except `self` or `cls` if it is a method.
838
848
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
839
863
"""
840
864
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 )
843
881
if match :
844
882
docstring_args .add (match .group (1 ))
845
883
yield from ConventionChecker ._check_missing_args (
0 commit comments