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.
@@ -854,10 +864,38 @@ def _check_args_section(docstring, definition, context):
854
864
* The section documents all function arguments (D417)
855
865
except `self` or `cls` if it is a method.
856
866
867
+ Documentation for each arg should start at the same indentation
868
+ level. For example, in this case x and y are distinguishable::
869
+
870
+ Args:
871
+ x: Lorem ipsum dolor sit amet
872
+ y: Ut enim ad minim veniam
873
+
874
+ In the case below, we only recognize x as a documented parameter
875
+ because the rest of the content is indented as if it belongs
876
+ to the description for x::
877
+
878
+ Args:
879
+ x: Lorem ipsum dolor sit amet
880
+ y: Ut enim ad minim veniam
857
881
"""
858
882
docstring_args = set ()
859
- for line in context .following_lines :
860
- match = ConventionChecker .GOOGLE_ARGS_REGEX .match (line )
883
+ # normalize leading whitespace
884
+ args_content = dedent ("\n " .join (context .following_lines )).strip ()
885
+
886
+ args_sections = []
887
+ for line in args_content .splitlines (keepends = True ):
888
+ if not line [:1 ].isspace ():
889
+ # This line is the start of documentation for the next
890
+ # parameter because it doesn't start with any whitespace.
891
+ args_sections .append (line )
892
+ else :
893
+ # This is a continuation of documentation for the last
894
+ # parameter because it does start with whitespace.
895
+ args_sections [- 1 ] += line
896
+
897
+ for section in args_sections :
898
+ match = ConventionChecker .GOOGLE_ARGS_REGEX .match (section )
861
899
if match :
862
900
docstring_args .add (match .group (1 ))
863
901
yield from ConventionChecker ._check_missing_args (
0 commit comments