Skip to content

Commit de613c2

Browse files
DanielNoordadam-grant-hendry
authored andcommitted
Fix and refactors for docparams extension (#7398)
* Fix and refactors for ``docparams`` extension The ``re_only_desc`` regex did not match for white and characters after ``\n``, so some description-only lines weren't getting matched. In addition, lookaheads were added to ``re_param_line`` (i.e. make sure the type group is not followed by a new line (``\n``)). Lastly, named groups (ala Perl regular expressions) were added for slightly improved clarity. Co-authored-by: Hendry, Adam <[email protected]>
1 parent e63a352 commit de613c2

File tree

5 files changed

+53
-22
lines changed

5 files changed

+53
-22
lines changed

doc/whatsnew/fragments/7398.other

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The ``docparams`` extension now considers typing in Numpy style docstrings
2+
as "documentation" for the ``missing-param-doc`` message.
3+
4+
Refs #7398

pylint/extensions/_check_docs_utils.py

+27-13
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class SphinxDocstring(Docstring):
247247

248248
re_multiple_simple_type = r"""
249249
(?:{container_type}|{type})
250-
(?:(?:\s+(?:of|or)\s+|\s*,\s*)(?:{container_type}|{type}))*
250+
(?:(?:\s+(?:of|or)\s+|\s*,\s*|\s+\|\s+)(?:{container_type}|{type}))*
251251
""".format(
252252
type=re_type, container_type=re_simple_container_type
253253
)
@@ -449,7 +449,7 @@ class GoogleDocstring(Docstring):
449449

450450
re_multiple_type = r"""
451451
(?:{container_type}|{type}|{xref})
452-
(?:(?:\s+(?:of|or)\s+|\s*,\s*)(?:{container_type}|{type}|{xref}))*
452+
(?:(?:\s+(?:of|or)\s+|\s*,\s*|\s+\|\s+)(?:{container_type}|{type}|{xref}))*
453453
""".format(
454454
type=re_type, xref=re_xref, container_type=re_container_type
455455
)
@@ -728,22 +728,25 @@ class NumpyDocstring(GoogleDocstring):
728728
re.X | re.S | re.M,
729729
)
730730

731-
re_default_value = r"""((['"]\w+\s*['"])|(True)|(False)|(None))"""
731+
re_default_value = r"""((['"]\w+\s*['"])|(\d+)|(True)|(False)|(None))"""
732732

733733
re_param_line = re.compile(
734734
rf"""
735-
\s* (\*{{0,2}}\w+)(\s?(:|\n)) # identifier with potential asterisks
735+
\s* (?P<param_name>\*{{0,2}}\w+)(\s?(:|\n)) # identifier with potential asterisks
736736
\s*
737-
(
737+
(?P<param_type>
738738
(
739739
({GoogleDocstring.re_multiple_type}) # default type declaration
740740
(,\s+optional)? # optional 'optional' indication
741741
)?
742742
(
743743
{{({re_default_value},?\s*)+}} # set of default values
744744
)?
745-
\n)?
746-
\s* (.*) # optional description
745+
(?:$|\n)
746+
)?
747+
(
748+
\s* (?P<param_desc>.*) # optional description
749+
)?
747750
""",
748751
re.X | re.S,
749752
)
@@ -794,15 +797,26 @@ def match_param_docs(self) -> tuple[set[str], set[str]]:
794797
continue
795798

796799
# check if parameter has description only
797-
re_only_desc = re.match(r"\s* (\*{0,2}\w+)\s*:?\n", entry)
800+
re_only_desc = re.match(r"\s*(\*{0,2}\w+)\s*:?\n\s*\w*$", entry)
798801
if re_only_desc:
799-
param_name = match.group(1)
800-
param_desc = match.group(2)
802+
param_name = match.group("param_name")
803+
param_desc = match.group("param_type")
801804
param_type = None
802805
else:
803-
param_name = match.group(1)
804-
param_type = match.group(3)
805-
param_desc = match.group(4)
806+
param_name = match.group("param_name")
807+
param_type = match.group("param_type")
808+
param_desc = match.group("param_desc")
809+
# The re_param_line pattern needs to match multi-line which removes the ability
810+
# to match a single line description like 'arg : a number type.'
811+
# We are not trying to determine whether 'a number type' is correct typing
812+
# but we do accept it as typing as it is in the place where typing
813+
# should be
814+
if param_type is None and re.match(r"\s*(\*{0,2}\w+)\s*:.+$", entry):
815+
param_type = param_desc
816+
# If the description is "" but we have a type description
817+
# we consider the description to be the type
818+
if not param_desc and param_type:
819+
param_desc = param_type
806820

807821
if param_type:
808822
params_with_type.add(param_name)

tests/functional/ext/docparams/missing_param_doc.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def foobar4(arg1, arg2): #[missing-param-doc, missing-type-doc]
3030
"""
3131
print(arg1, arg2)
3232

33-
def foobar5(arg1, arg2): #[missing-param-doc, missing-type-doc]
33+
def foobar5(arg1, arg2): #[missing-type-doc]
3434
"""function foobar ...
3535
Parameters
3636
----------
@@ -63,7 +63,7 @@ def foobar8(arg1): #[missing-any-param-doc]
6363

6464
print(arg1)
6565

66-
def foobar9(arg1, arg2, arg3): #[missing-param-doc]
66+
def foobar9(arg1, arg2, arg3):
6767
"""function foobar ...
6868
Parameters
6969
----------
@@ -73,7 +73,7 @@ def foobar9(arg1, arg2, arg3): #[missing-param-doc]
7373
"""
7474
print(arg1, arg2, arg3)
7575

76-
def foobar10(arg1, arg2, arg3): #[missing-param-doc, missing-type-doc]
76+
def foobar10(arg1, arg2, arg3): #[missing-type-doc]
7777
"""function foobar ...
7878
Parameters
7979
----------
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
missing-any-param-doc:3:0:3:11:foobar1:"Missing any documentation in ""foobar1""":HIGH
22
missing-any-param-doc:8:0:8:11:foobar2:"Missing any documentation in ""foobar2""":HIGH
3-
missing-param-doc:15:0:15:11:foobar3:"""arg1, arg2, arg3"" missing in parameter documentation":HIGH
3+
missing-param-doc:15:0:15:11:foobar3:"""arg2"" missing in parameter documentation":HIGH
44
missing-type-doc:15:0:15:11:foobar3:"""arg2"" missing in parameter type documentation":HIGH
55
missing-param-doc:24:0:24:11:foobar4:"""arg2"" missing in parameter documentation":HIGH
66
missing-type-doc:24:0:24:11:foobar4:"""arg2"" missing in parameter type documentation":HIGH
7-
missing-param-doc:33:0:33:11:foobar5:"""arg2"" missing in parameter documentation":HIGH
87
missing-type-doc:33:0:33:11:foobar5:"""arg1"" missing in parameter type documentation":HIGH
9-
missing-param-doc:43:0:43:11:foobar6:"""arg2, arg3"" missing in parameter documentation":HIGH
8+
missing-param-doc:43:0:43:11:foobar6:"""arg3"" missing in parameter documentation":HIGH
109
missing-type-doc:43:0:43:11:foobar6:"""arg3"" missing in parameter type documentation":HIGH
1110
missing-any-param-doc:53:0:53:11:foobar7:"Missing any documentation in ""foobar7""":HIGH
1211
missing-any-param-doc:61:0:61:11:foobar8:"Missing any documentation in ""foobar8""":HIGH
13-
missing-param-doc:66:0:66:11:foobar9:"""arg1, arg2, arg3"" missing in parameter documentation":HIGH
14-
missing-param-doc:76:0:76:12:foobar10:"""arg2"" missing in parameter documentation":HIGH
1512
missing-type-doc:76:0:76:12:foobar10:"""arg1, arg3"" missing in parameter type documentation":HIGH
1613
missing-any-param-doc:88:0:88:12:foobar11:"Missing any documentation in ""foobar11""":HIGH
17-
missing-param-doc:97:0:97:12:foobar12:"""arg1, arg3"" missing in parameter documentation":HIGH
14+
missing-param-doc:97:0:97:12:foobar12:"""arg3"" missing in parameter documentation":HIGH
1815
missing-type-doc:97:0:97:12:foobar12:"""arg2, arg3"" missing in parameter type documentation":HIGH

tests/functional/ext/docparams/parameter/missing_param_doc_required_Numpy.py

+16
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ def test_ignores_optional_specifier_numpy(param, param2="all"):
392392
"""
393393
return param, param2
394394

395+
395396
def test_with_list_of_default_values(arg, option, option2):
396397
"""Reported in https://github.com/PyCQA/pylint/issues/4035.
397398
@@ -406,3 +407,18 @@ def test_with_list_of_default_values(arg, option, option2):
406407
407408
"""
408409
return arg, option, option2
410+
411+
412+
def test_with_descriptions_instead_of_typing(arg, axis, option):
413+
"""We choose to accept description in place of typing as well.
414+
415+
See: https://github.com/PyCQA/pylint/pull/7398.
416+
417+
Parameters
418+
----------
419+
arg : a number type.
420+
axis : int or None
421+
option : {"y", "n"}
422+
Do I do it?
423+
"""
424+
return arg, option

0 commit comments

Comments
 (0)