예제 #1
0
 def check_single_constructor_params(self, class_doc: Docstring,
                                     init_doc: Docstring,
                                     class_node: nodes.ClassDef) -> None:
     if class_doc.has_params() and init_doc.has_params():
         self.add_message("multiple-constructor-doc",
                          args=(class_node.name, ),
                          node=class_node)
예제 #2
0
    def check_functiondef_params(self, node: nodes.FunctionDef,
                                 node_doc: Docstring) -> None:
        node_allow_no_param = None
        if node.name in self.constructor_names:
            class_node = checker_utils.node_frame_class(node)
            if class_node is not None:
                class_doc = utils.docstringify(
                    class_node.doc_node,
                    self.linter.config.default_docstring_type)
                self.check_single_constructor_params(class_doc, node_doc,
                                                     class_node)

                # __init__ or class docstrings can have no parameters documented
                # as long as the other documents them.
                node_allow_no_param = (class_doc.has_params() or
                                       class_doc.params_documented_elsewhere()
                                       or None)
                class_allow_no_param = (node_doc.has_params() or
                                        node_doc.params_documented_elsewhere()
                                        or None)

                self.check_arguments_in_docstring(class_doc, node.args,
                                                  class_node,
                                                  class_allow_no_param)

        self.check_arguments_in_docstring(node_doc, node.args, node,
                                          node_allow_no_param)
예제 #3
0
    def check_functiondef_yields(self, node: nodes.FunctionDef,
                                 node_doc: Docstring) -> None:
        if not node_doc.supports_yields or node.is_abstract():
            return

        if (node_doc.has_yields()
                or node_doc.has_yields_type()) and not node.is_generator():
            self.add_message("redundant-yields-doc", node=node)
예제 #4
0
    def check_functiondef_returns(self, node: nodes.FunctionDef,
                                  node_doc: Docstring) -> None:
        if (not node_doc.supports_yields
                and node.is_generator()) or node.is_abstract():
            return

        return_nodes = node.nodes_of_class(astroid.Return)
        if (node_doc.has_returns() or node_doc.has_rtype()) and not any(
                utils.returns_something(ret_node)
                for ret_node in return_nodes):
            self.add_message("redundant-returns-doc", node=node)
예제 #5
0
    def check_arguments_in_docstring(
        self,
        doc: Docstring,
        arguments_node: astroid.Arguments,
        warning_node: astroid.NodeNG,
        accept_no_param_doc: Optional[bool] = None,
    ):
        """Check that all parameters are consistent with the parameters mentioned
        in the parameter documentation (e.g. the Sphinx tags 'param' and 'type').

        * Undocumented parameters except 'self' are noticed.
        * Undocumented parameter types except for 'self' and the ``*<args>``
          and ``**<kwargs>`` parameters are noticed.
        * Parameters mentioned in the parameter documentation that don't or no
          longer exist in the function parameter list are noticed.
        * If the text "For the parameters, see" or "For the other parameters,
          see" (ignoring additional whitespace) is mentioned in the docstring,
          missing parameter documentation is tolerated.
        * If there's no Sphinx style, Google style or NumPy style parameter
          documentation at all, i.e. ``:param`` is never mentioned etc., the
          checker assumes that the parameters are documented in another format
          and the absence is tolerated.

        :param doc: Docstring for the function, method or class.
        :type doc: :class:`Docstring`

        :param arguments_node: Arguments node for the function, method or
            class constructor.
        :type arguments_node: :class:`astroid.scoped_nodes.Arguments`

        :param warning_node: The node to assign the warnings to
        :type warning_node: :class:`astroid.scoped_nodes.Node`

        :param accept_no_param_doc: Whether to allow no parameters to be
            documented. If None then this value is read from the configuration.
        :type accept_no_param_doc: bool or None
        """
        # Tolerate missing param or type declarations if there is a link to
        # another method carrying the same name.
        if not doc.doc:
            return

        if accept_no_param_doc is None:
            accept_no_param_doc = self.linter.namespace.accept_no_param_doc
        tolerate_missing_params = doc.params_documented_elsewhere()

        # Collect the function arguments.
        expected_argument_names = {arg.name for arg in arguments_node.args}
        expected_argument_names.update(arg.name
                                       for arg in arguments_node.kwonlyargs)
        not_needed_type_in_docstring = self.not_needed_param_in_docstring.copy(
        )

        expected_but_ignored_argument_names = set()
        ignored_argument_names = get_global_option(self,
                                                   "ignored-argument-names")
        if ignored_argument_names:
            expected_but_ignored_argument_names = {
                arg
                for arg in expected_argument_names
                if ignored_argument_names.match(arg)
            }

        if arguments_node.vararg is not None:
            expected_argument_names.add(f"*{arguments_node.vararg}")
            not_needed_type_in_docstring.add(f"*{arguments_node.vararg}")
        if arguments_node.kwarg is not None:
            expected_argument_names.add(f"**{arguments_node.kwarg}")
            not_needed_type_in_docstring.add(f"**{arguments_node.kwarg}")
        params_with_doc, params_with_type = doc.match_param_docs()
        # Tolerate no parameter documentation at all.
        if not params_with_doc and not params_with_type and accept_no_param_doc:
            tolerate_missing_params = True

        # This is before the update of param_with_type because this must check only
        # the type documented in a docstring, not the one using pep484
        # See #4117 and #4593
        self._compare_ignored_args(
            params_with_type,
            "useless-type-doc",
            expected_but_ignored_argument_names,
            warning_node,
        )
        for index, arg_name in enumerate(arguments_node.args):
            if arguments_node.annotations[index]:
                params_with_type.add(arg_name.name)
        for index, arg_name in enumerate(arguments_node.kwonlyargs):
            if arguments_node.kwonlyargs_annotations[index]:
                params_with_type.add(arg_name.name)

        if not tolerate_missing_params:
            missing_param_doc = (expected_argument_names - params_with_doc) - (
                self.not_needed_param_in_docstring
                | expected_but_ignored_argument_names)
            missing_type_doc = (expected_argument_names - params_with_type) - (
                not_needed_type_in_docstring
                | expected_but_ignored_argument_names)
            if (missing_param_doc == expected_argument_names ==
                    missing_type_doc and len(expected_argument_names) != 0):
                self.add_message(
                    "missing-any-param-doc",
                    args=(warning_node.name, ),
                    node=warning_node,
                )
            else:
                self._compare_missing_args(
                    params_with_doc,
                    "missing-param-doc",
                    self.not_needed_param_in_docstring
                    | expected_but_ignored_argument_names,
                    expected_argument_names,
                    warning_node,
                )
                self._compare_missing_args(
                    params_with_type,
                    "missing-type-doc",
                    not_needed_type_in_docstring
                    | expected_but_ignored_argument_names,
                    expected_argument_names,
                    warning_node,
                )

        self._compare_different_args(
            params_with_doc,
            "differing-param-doc",
            self.not_needed_param_in_docstring,
            expected_argument_names,
            warning_node,
        )
        self._compare_different_args(
            params_with_type,
            "differing-type-doc",
            not_needed_type_in_docstring,
            expected_argument_names,
            warning_node,
        )
        self._compare_ignored_args(
            params_with_doc,
            "useless-param-doc",
            expected_but_ignored_argument_names,
            warning_node,
        )