diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | doc/whatsnew/2.12.rst | 5 | ||||
-rw-r--r-- | pylint/extensions/_check_docs_utils.py | 39 | ||||
-rw-r--r-- | tests/extensions/test_check_docs.py | 10 |
4 files changed, 53 insertions, 6 deletions
@@ -103,6 +103,11 @@ Release date: TBA Closes #3733 +* ``mising-param-doc`` now correctly handles Numpy parameter documentation without + explicit typing + + Closes #5222 + * Update ``literal-comparison``` checker to ignore tuple literals Closes #3031 diff --git a/doc/whatsnew/2.12.rst b/doc/whatsnew/2.12.rst index 0f16e4bdd..627a5eb07 100644 --- a/doc/whatsnew/2.12.rst +++ b/doc/whatsnew/2.12.rst @@ -123,3 +123,8 @@ Other Changes keyword parameters Closes #3733 + +* ``mising-param-doc`` now correctly handles Numpy parameter documentation without + explicit typing + + Closes #5222 diff --git a/pylint/extensions/_check_docs_utils.py b/pylint/extensions/_check_docs_utils.py index 52f9e470c..92f91847c 100644 --- a/pylint/extensions/_check_docs_utils.py +++ b/pylint/extensions/_check_docs_utils.py @@ -23,7 +23,7 @@ """Utility methods for docstring checking.""" import re -from typing import List +from typing import List, Set, Tuple import astroid from astroid import nodes @@ -731,9 +731,8 @@ class NumpyDocstring(GoogleDocstring): re_param_line = re.compile( fr""" - \s* (\*{{0,2}}\w+) # identifier with potential asterisks - \s* : - \s* (?:({GoogleDocstring.re_multiple_type})(?:,\s+optional)?)? # optional type declaration + \s* (\*{{0,2}}\w+)(\s?(:|\n)) # identifier with potential asterisks + \s* (?:({GoogleDocstring.re_multiple_type})(?:,\s+optional)?\n)? # optional type declaration \s* (.*) # optional description """, re.X | re.S, @@ -772,6 +771,38 @@ class NumpyDocstring(GoogleDocstring): supports_yields = True + def match_param_docs(self) -> Tuple[Set[str], Set[str]]: + """Matches parameter documentation section to parameter documentation rules""" + params_with_doc = set() + params_with_type = set() + + entries = self._parse_section(self.re_param_section) + print(entries) + entries.extend(self._parse_section(self.re_keyword_param_section)) + for entry in entries: + match = self.re_param_line.match(entry) + if not match: + continue + + # check if parameter has description only + re_only_desc = re.match(r"\s* (\*{0,2}\w+)\s*:?\n", entry) + if re_only_desc: + param_name = match.group(1) + param_desc = match.group(2) + param_type = None + else: + param_name = match.group(1) + param_type = match.group(3) + param_desc = match.group(4) + + if param_type: + params_with_type.add(param_name) + + if param_desc: + params_with_doc.add(param_name) + + return params_with_doc, params_with_type + @staticmethod def min_section_indent(section_match): return len(section_match.group(1)) diff --git a/tests/extensions/test_check_docs.py b/tests/extensions/test_check_docs.py index 79836c21a..5fdbc0ee3 100644 --- a/tests/extensions/test_check_docs.py +++ b/tests/extensions/test_check_docs.py @@ -1338,13 +1338,17 @@ class TestParamDocChecker(CheckerTestCase): def test_finds_args_without_type_numpy(self) -> None: node = astroid.extract_node( ''' - def my_func(named_arg, *args): + def my_func(named_arg, typed_arg: bool, untyped_arg, *args): """The docstring Args ---- named_arg : object Returned + typed_arg + Other argument without numpy type annotation + untyped_arg + Other argument without any type annotation *args : Optional Arguments @@ -1357,7 +1361,9 @@ class TestParamDocChecker(CheckerTestCase): return named_arg ''' ) - with self.assertNoMessages(): + with self.assertAddsMessages( + MessageTest(msg_id="missing-type-doc", node=node, args=("untyped_arg",)) + ): self.checker.visit_functiondef(node) def test_finds_args_with_xref_type_google(self) -> None: |