@@ -191,15 +191,15 @@ def test_parameter_docs(module, prefix):
191
191
continue
192
192
if verbose > 3 :
193
193
print (f" Checking keyword argument { kwargname } " )
194
- assert _check_parameter_docs (
194
+ _check_parameter_docs (
195
195
name , kwargname , inspect .getdoc (obj ),
196
196
prefix = prefix )
197
197
198
198
# Make sure this argument is documented properly in docstring
199
199
else :
200
200
if verbose > 3 :
201
201
print (f" Checking argument { argname } " )
202
- assert _check_parameter_docs (
202
+ _check_parameter_docs (
203
203
name , argname , docstring , prefix = prefix )
204
204
205
205
@@ -257,24 +257,46 @@ def test_deprecated_functions(module, prefix):
257
257
# Utility function to check for an argument in a docstring
258
258
def _check_parameter_docs (funcname , argname , docstring , prefix = "" ):
259
259
funcname = prefix + funcname
260
- if re .search (
260
+
261
+ # Find the "Parameters" section of docstring, where we start searching
262
+ if not (match := re .search (r"\nParameters\n----" , docstring )):
263
+ pytest .fail (f"{ funcname } docstring missing Parameters section" )
264
+ else :
265
+ start = match .start ()
266
+
267
+ # Find the "Returns" section of the docstring (to be skipped, if present)
268
+ match_returns = re .search (r"\nReturns\n----" , docstring )
269
+
270
+ # Find the "Other Parameters" section of the docstring, if present
271
+ match_other = re .search (r"\nOther Parameters\n----" , docstring )
272
+
273
+ # Remove the returns section from docstring, in case output arguments
274
+ # match input argument names (it happens...)
275
+ if match_other and match_returns :
276
+ docstring = docstring [start :match_returns .start ()] + \
277
+ docstring [match_other .start ():]
278
+ else :
279
+ docstring = docstring [start :]
280
+
281
+ # Look for the parameter name in the docstring
282
+ if match := re .search (
261
283
"\n " + r"((\w+|\.{3}), )*" + argname + r"(, (\w+|\.{3}))*:" ,
262
284
docstring ):
263
285
# Found the string, but not in numpydoc form
264
286
if verbose :
265
287
print (f" { funcname } : { argname } docstring missing space" )
266
288
warnings .warn (f"{ funcname } '{ argname } ' docstring missing space" )
267
- return True
268
289
269
- elif not re .search (
290
+ elif not ( match := re .search (
270
291
"\n " + r"((\w+|\.{3}), )*" + argname + r"(, (\w+|\.{3}))* :" ,
271
- docstring ):
272
- # return False
273
- #
274
- # Just issue a warning for now
292
+ docstring )):
275
293
if verbose :
276
294
print (f" { funcname } : { argname } not documented" )
277
- warnings .warn (f"{ funcname } '{ argname } ' not documented" )
278
- return False
279
-
280
- return True
295
+ pytest .fail (f"{ funcname } '{ argname } ' not documented" )
296
+
297
+ # Make sure there isn't another instance
298
+ second_match = re .search (
299
+ "\n " + r"((\w+|\.{3}), )*" + argname + r"(, (\w+|\.{3}))*[ ]*:" ,
300
+ docstring [match .end ():])
301
+ if second_match :
302
+ pytest .fail (f"{ funcname } '{ argname } ' documented twice" )
0 commit comments