def check_parameters()

in tools/pylint-extensions/azure-pylint-guidelines-checker/pylint_guidelines_checker.py [0:0]


    def check_parameters(self, node):
        """Parse the docstring for any params and types
        and compares it to the function's parameters.

        Throws a pylint error if...
        1. Missing param in docstring.
        2. Missing a param type in the docstring.
        3. Missing a return doc in the docstring when a function returns something.
        4. Missing an rtype in the docstring when a function returns something.
        5. Extra params in docstring that aren't function parameters. Change to keywords.
        6. Docstring has a keyword that isn't a keyword-only argument in the function signature.

        :param node: ast.ClassDef or ast.FunctionDef
        :return: None
        """
        arg_names = []
        method_keyword_only_args = []
        vararg_name = None
        # specific case for constructor where docstring found in class def
        if isinstance(node, astroid.ClassDef):
            for constructor in node.body:
                if (
                    isinstance(constructor, astroid.FunctionDef)
                    and constructor.name == "__init__"
                ):
                    arg_names = [arg.name for arg in constructor.args.args]
                    method_keyword_only_args = [
                        arg.name for arg in constructor.args.kwonlyargs
                    ]
                    vararg_name = node.args.vararg
                    break

        if isinstance(node, astroid.FunctionDef):
            arg_names = [arg.name for arg in node.args.args]
            method_keyword_only_args = [arg.name for arg in node.args.kwonlyargs]
            vararg_name = node.args.vararg

        try:
            # check for incorrect type :class to prevent splitting
            docstring = node.doc_node.value.replace(":class:", "CLASS ")
            # not every method will have a docstring so don't crash here, just return
            docstring = docstring.split(":")
        except AttributeError:
            return

        # If there is a vararg, treat it as a param
        if vararg_name:
            arg_names.append(vararg_name)

        docparams = {}
        docstring_keyword_args = {}
        for idx, line in enumerate(docstring):
            # check for keyword args in docstring
            docstring_keyword_args.update(
                self._find_keyword(line, docstring, idx, docstring_keyword_args)
            )

            # check for params in docstring
            docparams.update(self._find_param(line, docstring, idx, docparams))

        # check that all params are documented
        missing_params = []
        for param in arg_names:
            if param == "self" or param == "cls":
                continue
            if param not in docparams:
                missing_params.append(param)

        # check that all keyword-only args are documented
        missing_kwonly_args = list(
            set(docstring_keyword_args) ^ set(method_keyword_only_args)
        )

        if missing_params:
            self.add_message(
                msgid="docstring-missing-param",
                args=(", ".join(missing_params)),
                node=node,
                confidence=None,
            )

        if missing_kwonly_args:
            self.add_message(
                msgid="docstring-keyword-should-match-keyword-only",
                args=(", ".join(missing_kwonly_args)),
                node=node,
                confidence=None,
            )

        # check that all types are formatted correctly
        add_keyword_type_warnings = [
            keyword
            for keyword, doc_type in docstring_keyword_args.items()
            if doc_type and "CLASS" in doc_type
        ]
        if len(add_keyword_type_warnings) > 0:
            self.add_message(
                msgid="docstring-type-do-not-use-class",
                args=(", ".join(add_keyword_type_warnings)),
                node=node,
                confidence=None,
            )

        add_docparams_type_warnings = [
            param
            for param, doc_type in docparams.items()
            if doc_type and "CLASS" in doc_type
        ]
        if len(add_docparams_type_warnings) > 0:
            self.add_message(
                msgid="docstring-type-do-not-use-class",
                args=(", ".join(add_docparams_type_warnings)),
                node=node,
                confidence=None,
            )

        # check if we have a type for each param and check if documented params that should be keywords
        missing_types = []
        should_be_keywords = []
        for param in docparams:
            if docparams[param] is None:
                missing_types.append(param)
            if param not in arg_names:
                should_be_keywords.append(param)

        if missing_types:
            self.add_message(
                msgid="docstring-missing-type",
                args=(", ".join(missing_types)),
                node=node,
                confidence=None,
            )

        if should_be_keywords:
            self.add_message(
                msgid="docstring-should-be-keyword",
                args=(", ".join(should_be_keywords)),
                node=node,
                confidence=None,
            )