Ejemplo n.º 1
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     self._check_nonlocal_and_global(node)
     self._check_name_used_prior_global(node)
     if not redefined_by_decorator(
             node) and not utils.is_registered_in_singledispatch_function(
                 node):
         self._check_redefinition(
             node.is_method() and "method" or "function", node)
     # checks for max returns, branch, return in __init__
     returns = node.nodes_of_class(nodes.Return,
                                   skip_klass=(nodes.FunctionDef,
                                               nodes.ClassDef))
     if node.is_method() and node.name == "__init__":
         if node.is_generator():
             self.add_message("init-is-generator", node=node)
         else:
             values = [r.value for r in returns]
             # Are we returning anything but None from constructors
             if any(v for v in values if not utils.is_none(v)):
                 self.add_message("return-in-init", node=node)
     # Check for duplicate names by clustering args with same name for detailed report
     arg_clusters = {}
     arguments: Iterator[Any] = filter(
         None, [node.args.args, node.args.kwonlyargs])
     for arg in itertools.chain.from_iterable(arguments):
         if arg.name in arg_clusters:
             self.add_message(
                 "duplicate-argument-name",
                 node=arg,
                 args=(arg.name, ),
                 confidence=HIGH,
             )
         else:
             arg_clusters[arg.name] = arg
Ejemplo n.º 2
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        if self.linter.namespace.no_docstring_rgx.match(node.name) is None:
            ftype = "method" if node.is_method() else "function"
            if (is_property_setter(node) or is_property_deleter(node)
                    or is_overload_stub(node)):
                return

            if isinstance(node.parent.frame(future=True), nodes.ClassDef):
                overridden = False
                confidence = (interfaces.INFERENCE if utils.has_known_bases(
                    node.parent.frame(
                        future=True)) else interfaces.INFERENCE_FAILURE)
                # check if node is from a method overridden by its ancestor
                for ancestor in node.parent.frame(future=True).ancestors():
                    if ancestor.qname() == "builtins.object":
                        continue
                    if node.name in ancestor and isinstance(
                            ancestor[node.name], nodes.FunctionDef):
                        overridden = True
                        break
                self._check_docstring(
                    ftype,
                    node,
                    report_missing=not overridden,
                    confidence=confidence  # type: ignore[arg-type]
                )
            elif isinstance(node.parent.frame(future=True), nodes.Module):
                self._check_docstring(ftype, node)  # type: ignore[arg-type]
            else:
                return
Ejemplo n.º 3
0
    def leave_functiondef(self, node: nodes.FunctionDef) -> None:
        """On method node, check if this method couldn't be a function.

        ignore class, static and abstract methods, initializer,
        methods overridden from a parent class.
        """
        if node.is_method():
            first = self._first_attrs.pop()
            if first is None:
                return
            class_node = node.parent.frame(future=True)
            if (
                self._meth_could_be_func
                and node.type == "method"
                and node.name not in PYMETHODS
                and not (
                    node.is_abstract()
                    or overrides_a_method(class_node, node.name)
                    or decorated_with_property(node)
                    or _has_bare_super_call(node)
                    or is_protocol_class(class_node)
                    or is_overload_stub(node)
                )
            ):
                self.add_message("no-self-use", node=node, confidence=INFERENCE)
Ejemplo n.º 4
0
def _determine_function_name_type(node: nodes.FunctionDef, config=None):
    """Determine the name type whose regex the function's name should match.

    :param node: A function node.
    :param config: Configuration from which to pull additional property classes.
    :type config: :class:`optparse.Values`

    :returns: One of ('function', 'method', 'attr')
    :rtype: str
    """
    property_classes, property_names = _get_properties(config)
    if not node.is_method():
        return "function"

    if is_property_setter(node) or is_property_deleter(node):
        # If the function is decorated using the prop_method.{setter,getter}
        # form, treat it like an attribute as well.
        return "attr"

    decorators = node.decorators.nodes if node.decorators else []
    for decorator in decorators:
        # If the function is a property (decorated with @property
        # or @abc.abstractproperty), the name type is 'attr'.
        if isinstance(
                decorator,
                nodes.Name) or (isinstance(decorator, nodes.Attribute)
                                and decorator.attrname in property_names):
            inferred = utils.safe_infer(decorator)
            if (inferred and hasattr(inferred, "qname")
                    and inferred.qname() in property_classes):
                return "attr"
    return "method"
Ejemplo n.º 5
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     """Check function name, docstring, arguments, redefinition,
     variable names, max locals.
     """
     if node.is_method():
         self.linter.stats.node_count["method"] += 1
     else:
         self.linter.stats.node_count["function"] += 1
     self._check_dangerous_default(node)
Ejemplo n.º 6
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        if not node.is_method():
            return

        inferred = _safe_infer_call_result(node, node)
        # Only want to check types that we are able to infer
        if (inferred and node.name in self._protocol_map
                and not is_function_body_ellipsis(node)):
            self._protocol_map[node.name](node, inferred)

        if node.name in PYMETHODS:
            self._check_unexpected_method_signature(node)
Ejemplo n.º 7
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        """Called when a FunctionDef node is visited."""
        if not node.is_method() or node.name != "__init__":
            return

        # Check that all arguments are annotated.
        # The first argument is "self".
        args = node.args
        annotations = (args.posonlyargs_annotations + args.annotations +
                       args.kwonlyargs_annotations)[1:]
        if args.vararg is not None:
            annotations.append(args.varargannotation)
        if args.kwarg is not None:
            annotations.append(args.kwargannotation)
        if not annotations or None in annotations:
            return

        # Check that return type is specified and it is "None".
        if not isinstance(node.returns,
                          nodes.Const) or node.returns.value is not None:
            self.add_message("hass-constructor-return", node=node)
Ejemplo n.º 8
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        # Do not emit any warnings if the method is just an implementation
        # of a base class method.
        confidence = interfaces.HIGH
        if node.is_method():
            if utils.overrides_a_method(node.parent.frame(future=True),
                                        node.name):
                return
            confidence = (interfaces.INFERENCE if utils.has_known_bases(
                node.parent.frame(
                    future=True)) else interfaces.INFERENCE_FAILURE)

        self._check_name(
            _determine_function_name_type(node, config=self.linter.config),
            node.name,
            node,
            confidence,
        )
        # Check argument names
        args = node.args.args
        if args is not None:
            self._recursive_check_names(args)
Ejemplo n.º 9
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        """check use of super"""
        # ignore actual functions or method within a new style class
        if not node.is_method():
            return
        klass = node.parent.frame()
        for stmt in node.nodes_of_class(nodes.Call):
            if node_frame_class(stmt) != node_frame_class(node):
                # Don't look down in other scopes.
                continue

            expr = stmt.func
            if not isinstance(expr, nodes.Attribute):
                continue

            call = expr.expr
            # skip the test if using super
            if not (isinstance(call, nodes.Call) and isinstance(
                    call.func, nodes.Name) and call.func.name == "super"):
                continue

            # super should not be used on an old style class
            if klass.newstyle or not has_known_bases(klass):
                # super first arg should not be the class
                if not call.args:
                    continue

                # calling super(type(self), self) can lead to recursion loop
                # in derived classes
                arg0 = call.args[0]
                if (isinstance(arg0, nodes.Call)
                        and isinstance(arg0.func, nodes.Name)
                        and arg0.func.name == "type"):
                    self.add_message("bad-super-call",
                                     node=call,
                                     args=("type", ))
                    continue

                # calling super(self.__class__, self) can lead to recursion loop
                # in derived classes
                if (len(call.args) >= 2
                        and isinstance(call.args[1], nodes.Name)
                        and call.args[1].name == "self"
                        and isinstance(arg0, nodes.Attribute)
                        and arg0.attrname == "__class__"):
                    self.add_message("bad-super-call",
                                     node=call,
                                     args=("self.__class__", ))
                    continue

                try:
                    supcls = call.args and next(call.args[0].infer(), None)
                except astroid.InferenceError:
                    continue

                if klass is not supcls:
                    name = None
                    # if supcls is not Uninferable, then supcls was inferred
                    # and use its name. Otherwise, try to look
                    # for call.args[0].name
                    if supcls:
                        name = supcls.name
                    elif call.args and hasattr(call.args[0], "name"):
                        name = call.args[0].name
                    if name:
                        self.add_message("bad-super-call",
                                         node=call,
                                         args=(name, ))
Ejemplo n.º 10
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     ftype = "method" if node.is_method() else "function"
     self._check_docstring(ftype, node)
Ejemplo n.º 11
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     if not node.is_method():
         return
     self._meth_could_be_func = True
     self._check_first_arg_for_type(node)
Ejemplo n.º 12
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     """Called when a FunctionDef node is visited."""
     for match in self._function_matchers:
         if node.name != match.function_name or node.is_method():
             continue
         self._check_function(node, match)