pylint/checkers/typecheck.py
def visit_call(self, node):
        """check that called functions/methods are inferred to callable objects,
        and that the arguments passed to the function match the parameters in
        the inferred function's definition
        """
        called = safe_infer(node.func)
        # only function, generator and object defining __call__ are allowed
        # Ignore instances of descriptors since astroid cannot properly handle them
        # yet
        if called and not called.callable():
            if isinstance(called, astroid.Instance) and (
                not has_known_bases(called)
                or (
                    isinstance(called.scope(), astroid.ClassDef)
                    and "__get__" in called.locals
                )
            ):
                # Don't emit if we can't make sure this object is callable.
                pass
            else:
                self.add_message("not-callable", node=node, args=node.func.as_string())

        self._check_uninferable_call(node)

        try:
            called, implicit_args, callable_name = _determine_callable(called)
        except ValueError:
            # Any error occurred during determining the function type, most of
            # those errors are handled by different warnings.
            return

        if called.args.args is None:
            # Built-in functions have no argument information.
            return

        if len(called.argnames()) != len(set(called.argnames())):
            # Duplicate parameter name (see duplicate-argument).  We can't really
            # make sense of the function call in this case, so just return.
            return

        # Build the set of keyword arguments, checking for duplicate keywords,
        # and count the positional arguments.
        call_site = astroid.arguments.CallSite.from_call(node)

        # Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}`
        for keyword in call_site.duplicated_keywords:
            self.add_message("repeated-keyword", node=node, args=(keyword,))

        if call_site.has_invalid_arguments() or call_site.has_invalid_keywords():
            # Can't make sense of this.
            return

        num_positional_args = len(call_site.positional_arguments)
        keyword_args = list(call_site.keyword_arguments.keys())

        # Determine if we don't have a context for our call and we use variadics.
        if isinstance(node.scope(), astroid.FunctionDef):
            has_no_context_positional_variadic = _no_context_variadic_positional(node)
            has_no_context_keywords_variadic = _no_context_variadic_keywords(node)
        else:
            has_no_context_positional_variadic = (
                has_no_context_keywords_variadic
            ) = False

        # These are coming from the functools.partial implementation in astroid
        already_filled_positionals = getattr(called, "filled_positionals", 0)
        already_filled_keywords = getattr(called, "filled_keywords", {})

        keyword_args += list(already_filled_keywords)
        num_positional_args += implicit_args + already_filled_positionals

        # Analyze the list of formal parameters.

        num_mandatory_parameters = len(called.args.args) - len(called.args.defaults)
        parameters = []
        parameter_name_to_index = {}
        for i, arg in enumerate(called.args.args):
            if isinstance(arg, astroid.Tuple):
                name = None
                # Don't store any parameter names within the tuple, since those
                # are not assignable from keyword arguments.
            else:
                assert isinstance(arg, astroid.AssignName)
                # This occurs with:
                #    def f( (a), (b) ): pass
                name = arg.name
                parameter_name_to_index[name] = i
            if i >= num_mandatory_parameters:
                defval = called.args.defaults[i - num_mandatory_parameters]
            else:
                defval = None
            parameters.append([(name, defval), False])

        kwparams = {}
        for i, arg in enumerate(called.args.kwonlyargs):
            if isinstance(arg, astroid.Keyword):
                name = arg.arg
            else:
                assert isinstance(arg, astroid.AssignName)
                name = arg.name
            kwparams[name] = [called.args.kw_defaults[i], False]

        # Match the supplied arguments against the function parameters.

        # 1. Match the positional arguments.
        for i in range(num_positional_args):
            if i < len(parameters):
                parameters[i][1] = True
            elif called.args.vararg is not None:
                # The remaining positional arguments get assigned to the *args
                # parameter.
                break
            else:
                # Too many positional arguments.
                self.add_message(
                    "too-many-function-args", node=node, args=(callable_name,)
                )
                break

        # 2. Match the keyword arguments.
        for keyword in keyword_args:
            if keyword in parameter_name_to_index:
                i = parameter_name_to_index[keyword]
                if parameters[i][1]:
                    # Duplicate definition of function parameter.

                    # Might be too hardcoded, but this can actually
                    # happen when using str.format and `self` is passed
                    # by keyword argument, as in `.format(self=self)`.
                    # It's perfectly valid to so, so we're just skipping
                    # it if that's the case.
                    if not (keyword == "self" and called.qname() in STR_FORMAT):
                        self.add_message(
                            "redundant-keyword-arg",
                            node=node,
                            args=(keyword, callable_name),
                        )
                else:
                    parameters[i][1] = True
            elif keyword in kwparams:
                if kwparams[keyword][1]:  # XXX is that even possible?
                    # Duplicate definition of function parameter.
                    self.add_message(
                        "redundant-keyword-arg",
                        node=node,
                        args=(keyword, callable_name),
                    )
                else:
                    kwparams[keyword][1] = True
            elif called.args.kwarg is not None:
                # The keyword argument gets assigned to the **kwargs parameter.
                pass
            else:
                # Unexpected keyword argument.
                self.add_message(
                    "unexpected-keyword-arg", node=node, args=(keyword, callable_name)
                )

        # 3. Match the **kwargs, if any.
        if node.kwargs:
            for i, [(name, defval), assigned] in enumerate(parameters):
                # Assume that *kwargs provides values for all remaining
                # unassigned named parameters.
                if name is not None:
                    parameters[i][1] = True
                else:
                    # **kwargs can't assign to tuples.
                    pass

        # Check that any parameters without a default have been assigned
        # values.
        for [(name, defval), assigned] in parameters:
            if (defval is None) and not assigned:
                if name is None:
                    display_name = "<tuple>"
                else:
                    display_name = repr(name)
                # TODO(cpopa): this should be removed after PyCQA/astroid/issues/177
                if not has_no_context_positional_variadic:
                    self.add_message(
                        "no-value-for-parameter",
                        node=node,
                        args=(display_name, callable_name),
                    )

        for name in kwparams:
            defval, assigned = kwparams[name]
            if defval is None and not assigned and not has_no_context_keywords_variadic:
                self.add_message("missing-kwoa", node=node, args=(name, callable_name))
def visit_call(self, node):
        """check that called functions/methods are inferred to callable objects,
        and that the arguments passed to the function match the parameters in
        the inferred function's definition
        """
        called = safe_infer(node.func)
        # only function, generator and object defining __call__ are allowed
        # Ignore instances of descriptors since astroid cannot properly handle them
        # yet
        if called and not called.callable():
            if isinstance(called, astroid.Instance) and (
                not has_known_bases(called)
                or (
                    isinstance(called.scope(), astroid.ClassDef)
                    and "__get__" in called.locals
                )
            ):
                # Don't emit if we can't make sure this object is callable.
                pass
            else:
                self.add_message("not-callable", node=node, args=node.func.as_string())

        self._check_uninferable_call(node)

        try:
            called, implicit_args, callable_name = _determine_callable(called)
        except ValueError:
            # Any error occurred during determining the function type, most of
            # those errors are handled by different warnings.
            return

        if called.args.args is None:
            # Built-in functions have no argument information.
            return

        if len(called.argnames()) != len(set(called.argnames())):
            # Duplicate parameter name (see duplicate-argument).  We can't really
            # make sense of the function call in this case, so just return.
            return

        # Build the set of keyword arguments, checking for duplicate keywords,
        # and count the positional arguments.
        call_site = astroid.arguments.CallSite.from_call(node)

        # Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}`
        for keyword in call_site.duplicated_keywords:
            self.add_message("repeated-keyword", node=node, args=(keyword,))

        if call_site.has_invalid_arguments() or call_site.has_invalid_keywords():
            # Can't make sense of this.
            return

        num_positional_args = len(call_site.positional_arguments)
        keyword_args = list(call_site.keyword_arguments.keys())

        # Determine if we don't have a context for our call and we use variadics.
        if isinstance(node.scope(), astroid.FunctionDef):
            has_no_context_positional_variadic = _no_context_variadic_positional(node)
            has_no_context_keywords_variadic = _no_context_variadic_keywords(node)
        else:
            has_no_context_positional_variadic = (
                has_no_context_keywords_variadic
            ) = False

        # These are coming from the functools.partial implementation in astroid
        already_filled_positionals = getattr(called, "filled_positionals", 0)
        already_filled_keywords = getattr(called, "filled_keywords", {})

        keyword_args += list(already_filled_keywords)
        num_positional_args += implicit_args + already_filled_positionals

        # Analyze the list of formal parameters.

        num_mandatory_parameters = len(called.args.args) - len(called.args.defaults)
        parameters = []
        parameter_name_to_index = {}
        for i, arg in enumerate(called.args.args):
            if isinstance(arg, astroid.Tuple):
                name = None
                # Don't store any parameter names within the tuple, since those
                # are not assignable from keyword arguments.
            else:
                assert isinstance(arg, astroid.AssignName)
                # This occurs with:
                #    def f( (a), (b) ): pass
                name = arg.name
                parameter_name_to_index[name] = i
            if i >= num_mandatory_parameters:
                defval = called.args.defaults[i - num_mandatory_parameters]
            else:
                defval = None
            parameters.append([(name, defval), False])

        kwparams = {}
        for i, arg in enumerate(called.args.kwonlyargs):
            if isinstance(arg, astroid.Keyword):
                name = arg.arg
            else:
                assert isinstance(arg, astroid.AssignName)
                name = arg.name
            kwparams[name] = [called.args.kw_defaults[i], False]

        # Match the supplied arguments against the function parameters.

        # 1. Match the positional arguments.
        for i in range(num_positional_args):
            if i < len(parameters):
                parameters[i][1] = True
            elif called.args.vararg is not None:
                # The remaining positional arguments get assigned to the *args
                # parameter.
                break
            else:
                # Too many positional arguments.
                self.add_message(
                    "too-many-function-args", node=node, args=(callable_name,)
                )
                break

        # 2. Match the keyword arguments.
        for keyword in keyword_args:
            if keyword in parameter_name_to_index:
                i = parameter_name_to_index[keyword]
                if parameters[i][1]:
                    # Duplicate definition of function parameter.

                    # Might be too hardcoded, but this can actually
                    # happen when using str.format and `self` is passed
                    # by keyword argument, as in `.format(self=self)`.
                    # It's perfectly valid to so, so we're just skipping
                    # it if that's the case.
                    if not (keyword == "self" and called.qname() in STR_FORMAT):
                        self.add_message(
                            "redundant-keyword-arg",
                            node=node,
                            args=(keyword, callable_name),
                        )
                else:
                    parameters[i][1] = True
            elif keyword in kwparams:
                if kwparams[keyword][1]:  # XXX is that even possible?
                    # Duplicate definition of function parameter.
                    self.add_message(
                        "redundant-keyword-arg",
                        node=node,
                        args=(keyword, callable_name),
                    )
                else:
                    kwparams[keyword][1] = True
            elif called.args.kwarg is not None:
                # The keyword argument gets assigned to the **kwargs parameter.
                pass
            else:
                # Unexpected keyword argument.
                self.add_message(
                    "unexpected-keyword-arg", node=node, args=(keyword, callable_name)
                )

        # 3. Match the **kwargs, if any.
        if node.kwargs:
            for i, [(name, defval), assigned] in enumerate(parameters):
                # Assume that *kwargs provides values for all remaining
                # unassigned named parameters.
                if name is not None:
                    parameters[i][1] = True
                else:
                    # **kwargs can't assign to tuples.
                    pass

        # Check that any parameters without a default have been assigned
        # values.
        for [(name, defval), assigned] in parameters:
            if (defval is None) and not assigned:
                if name is None:
                    display_name = "<tuple>"
                else:
                    display_name = repr(name)
                # TODO(cpopa): this should be removed after PyCQA/astroid/issues/177
                if not has_no_context_positional_variadic:
                    self.add_message(
                        "no-value-for-parameter",
                        node=node,
                        args=(display_name, callable_name),
                    )

        for name in kwparams:
            defval, assigned = kwparams[name]
            if defval is None and not assigned and not has_no_context_keywords_variadic:
                self.add_message("missing-kwoa", node=node, args=(name, callable_name))
def visit_call ( self , node ) : called = safe_infer ( node . func ) # only function, generator and object defining __call__ are allowed # Ignore instances of descriptors since astroid cannot properly handle them # yet if called and not called . callable ( ) : if isinstance ( called , astroid . Instance ) and ( not has_known_bases ( called ) or ( isinstance ( called . scope ( ) , astroid . ClassDef ) and "__get__" in called . locals ) ) : # Don't emit if we can't make sure this object is callable. pass else : self . add_message ( "not-callable" , node = node , args = node . func . as_string ( ) ) self . _check_uninferable_call ( node ) try : called , implicit_args , callable_name = _determine_callable ( called ) except ValueError : # Any error occurred during determining the function type, most of # those errors are handled by different warnings. return if called . args . args is None : # Built-in functions have no argument information. return if len ( called . argnames ( ) ) != len ( set ( called . argnames ( ) ) ) : # Duplicate parameter name (see duplicate-argument).  We can't really # make sense of the function call in this case, so just return. return # Build the set of keyword arguments, checking for duplicate keywords, # and count the positional arguments. call_site = astroid . arguments . CallSite . from_call ( node ) # Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}` for keyword in call_site . duplicated_keywords : self . add_message ( "repeated-keyword" , node = node , args = ( keyword , ) ) if call_site . has_invalid_arguments ( ) or call_site . has_invalid_keywords ( ) : # Can't make sense of this. return num_positional_args = len ( call_site . positional_arguments ) keyword_args = list ( call_site . keyword_arguments . keys ( ) ) # Determine if we don't have a context for our call and we use variadics. if isinstance ( node . scope ( ) , astroid . FunctionDef ) : has_no_context_positional_variadic = _no_context_variadic_positional ( node ) has_no_context_keywords_variadic = _no_context_variadic_keywords ( node ) else : has_no_context_positional_variadic = ( has_no_context_keywords_variadic ) = False # These are coming from the functools.partial implementation in astroid already_filled_positionals = getattr ( called , "filled_positionals" , 0 ) already_filled_keywords = getattr ( called , "filled_keywords" , { } ) keyword_args += list ( already_filled_keywords ) num_positional_args += implicit_args + already_filled_positionals # Analyze the list of formal parameters. num_mandatory_parameters = len ( called . args . args ) - len ( called . args . defaults ) parameters = [ ] parameter_name_to_index = { } for i , arg in enumerate ( called . args . args ) : if isinstance ( arg , astroid . Tuple ) : name = None # Don't store any parameter names within the tuple, since those # are not assignable from keyword arguments. else : assert isinstance ( arg , astroid . AssignName ) # This occurs with: #    def f( (a), (b) ): pass name = arg . name parameter_name_to_index [ name ] = i if i >= num_mandatory_parameters : defval = called . args . defaults [ i - num_mandatory_parameters ] else : defval = None parameters . append ( [ ( name , defval ) , False ] ) kwparams = { } for i , arg in enumerate ( called . args . kwonlyargs ) : if isinstance ( arg , astroid . Keyword ) : name = arg . arg else : assert isinstance ( arg , astroid . AssignName ) name = arg . name kwparams [ name ] = [ called . args . kw_defaults [ i ] , False ] # Match the supplied arguments against the function parameters. # 1. Match the positional arguments. for i in range ( num_positional_args ) : if i < len ( parameters ) : parameters [ i ] [ 1 ] = True elif called . args . vararg is not None : # The remaining positional arguments get assigned to the *args # parameter. break else : # Too many positional arguments. self . add_message ( "too-many-function-args" , node = node , args = ( callable_name , ) ) break # 2. Match the keyword arguments. for keyword in keyword_args : if keyword in parameter_name_to_index : i = parameter_name_to_index [ keyword ] if parameters [ i ] [ 1 ] : # Duplicate definition of function parameter. # Might be too hardcoded, but this can actually # happen when using str.format and `self` is passed # by keyword argument, as in `.format(self=self)`. # It's perfectly valid to so, so we're just skipping # it if that's the case. if not ( keyword == "self" and called . qname ( ) in STR_FORMAT ) : self . add_message ( "redundant-keyword-arg" , node = node , args = ( keyword , callable_name ) , ) else : parameters [ i ] [ 1 ] = True elif keyword in kwparams : if kwparams [ keyword ] [ 1 ] : # XXX is that even possible? # Duplicate definition of function parameter. self . add_message ( "redundant-keyword-arg" , node = node , args = ( keyword , callable_name ) , ) else : kwparams [ keyword ] [ 1 ] = True elif called . args . kwarg is not None : # The keyword argument gets assigned to the **kwargs parameter. pass else : # Unexpected keyword argument. self . add_message ( "unexpected-keyword-arg" , node = node , args = ( keyword , callable_name ) ) # 3. Match the **kwargs, if any. if node . kwargs : for i , [ ( name , defval ) , assigned ] in enumerate ( parameters ) : # Assume that *kwargs provides values for all remaining # unassigned named parameters. if name is not None : parameters [ i ] [ 1 ] = True else : # **kwargs can't assign to tuples. pass # Check that any parameters without a default have been assigned # values. for [ ( name , defval ) , assigned ] in parameters : if ( defval is None ) and not assigned : if name is None : display_name = "<tuple>" else : display_name = repr ( name ) # TODO(cpopa): this should be removed after PyCQA/astroid/issues/177 if not has_no_context_positional_variadic : self . add_message ( "no-value-for-parameter" , node = node , args = ( display_name , callable_name ) , ) for name in kwparams : defval , assigned = kwparams [ name ] if defval is None and not assigned and not has_no_context_keywords_variadic : self . add_message ( "missing-kwoa" , node = node , args = ( name , callable_name ) )
check that called functions/methods are inferred to callable objects,
        and that the arguments passed to the function match the parameters in
        the inferred function's definition
check that called functions / methods are inferred to callable objects and that the arguments passed to the function match the parameters in the inferred function s definition