@@ -191,15 +191,15 @@ def test_parameter_docs(module, prefix):
191191 continue
192192 if verbose > 3 :
193193 print (f" Checking keyword argument { kwargname } " )
194- assert _check_parameter_docs (
194+ _check_parameter_docs (
195195 name , kwargname , inspect .getdoc (obj ),
196196 prefix = prefix )
197197
198198 # Make sure this argument is documented properly in docstring
199199 else :
200200 if verbose > 3 :
201201 print (f" Checking argument { argname } " )
202- assert _check_parameter_docs (
202+ _check_parameter_docs (
203203 name , argname , docstring , prefix = prefix )
204204
205205
@@ -257,24 +257,46 @@ def test_deprecated_functions(module, prefix):
257257# Utility function to check for an argument in a docstring
258258def _check_parameter_docs (funcname , argname , docstring , prefix = "" ):
259259 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 (
261283 "\n " + r"((\w+|\.{3}), )*" + argname + r"(, (\w+|\.{3}))*:" ,
262284 docstring ):
263285 # Found the string, but not in numpydoc form
264286 if verbose :
265287 print (f" { funcname } : { argname } docstring missing space" )
266288 warnings .warn (f"{ funcname } '{ argname } ' docstring missing space" )
267- return True
268289
269- elif not re .search (
290+ elif not ( match := re .search (
270291 "\n " + r"((\w+|\.{3}), )*" + argname + r"(, (\w+|\.{3}))* :" ,
271- docstring ):
272- # return False
273- #
274- # Just issue a warning for now
292+ docstring )):
275293 if verbose :
276294 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