def matchCall(func_name, args, star_list_arg, star_dict_arg, num_defaults,
              positional, pairs, improved = False):
    # This is of incredible code complexity, but there really is no other way to
    # express this with less statements, branches, or variables.
    # pylint: disable=R0912,R0914,R0915

    assert type(positional) is tuple, positional
    assert type(pairs) in (tuple, list), pairs

    # Make a copy, we are going to modify it.
    pairs = list(pairs)

    result = {}

    assigned_tuple_params = []

    def assign(arg, value):
        if type(arg) is str:
            # Normal case:
            result[ arg ] = value
        else:
            # Tuple argument case:

            assigned_tuple_params.append(arg)
            value = iter(value.getIterationValues())

            for i, subarg in enumerate(arg):
                try:
                    subvalue = next(value)
                except StopIteration:
                    raise TooManyArguments(
                        ValueError(
                            "need more than %d %s to unpack" % (
                                i,
                                "values" if i > 1 else "value"
                            )
                        )
                    )

                # Recurse into tuple argument values, could be more tuples.
                assign(subarg, subvalue)

            # Check that not too many values we provided.
            try:
                next(value)
            except __HOLE__:
                pass
            else:
                raise TooManyArguments(
                    ValueError("too many values to unpack")
                )

    def isAssigned(arg):
        if type(arg) is str:
            return arg in result

        return arg in assigned_tuple_params

    num_pos = len(positional)
    num_total = num_pos + len(pairs)
    num_args = len(args)

    for arg, value in zip(args, positional):
        assign(arg, value)

    # Python3 does this check earlier.
    if python_version >= 300 and not star_dict_arg:
        for pair in pairs:
            if pair[0] not in args:
                message = "'%s' is an invalid keyword argument for this function" % pair[0]

                raise TooManyArguments(
                    TypeError(message)
                )

    if star_list_arg:
        if num_pos > num_args:
            assign(star_list_arg, positional[ -(num_pos-num_args) : ])
        else:
            assign(star_list_arg, ())
    elif 0 < num_args < num_total:
        if num_defaults == 0:
            if num_args == 1:
                raise TooManyArguments(
                    TypeError(
                        "%s() takes exactly one argument (%d given)" % (
                            func_name,
                            num_total
                        )
                    )
                )
            else:
                raise TooManyArguments(
                    TypeError(
                        "%s expected %d arguments, got %d" % (
                            func_name,
                            num_args,
                            num_total
                        )
                    )
                )

        else:
            raise TooManyArguments(
                TypeError(
                    "%s() takes at most %d %s (%d given)" % (
                        func_name,
                        num_args,
                        "argument" if num_args == 1 else "arguments",
                        num_total
                    )
                )
            )
    elif num_args == 0 and num_total:
        if star_dict_arg:
            if num_pos:
                # Could use num_pos, but Python also uses num_total.
                raise TooManyArguments(
                    TypeError(
                        "%s() takes exactly 0 arguments (%d given)" % (
                            func_name,
                            num_total
                        )
                    )
                )
        else:
            raise TooManyArguments(
                TypeError(
                    "%s() takes no arguments (%d given)" % (
                        func_name,
                        num_total
                    )
                )
            )

    named_argument_names = [
        pair[0]
        for pair in
        pairs
    ]

    for arg in args:
        if type(arg) is str and arg in named_argument_names:
            if isAssigned(arg):
                raise TooManyArguments(
                    TypeError(
                        "%s() got multiple values for keyword argument '%s'" % (
                            func_name,
                            arg
                        )
                    )
                )
            else:
                new_pairs = []

                for pair in pairs:
                    if arg == pair[0]:
                        assign(arg, pair[1])
                    else:
                        new_pairs.append(pair)

                assert len(new_pairs) == len(pairs) - 1

                pairs = new_pairs

    # Fill in any missing values with the None to indicate "default".
    if num_defaults > 0:
        for arg in args[ -num_defaults : ]:
            if not isAssigned(arg):
                assign(arg, None)

    if star_dict_arg:
        assign(star_dict_arg, pairs)
    elif pairs:
        unexpected = next(iter(dict(pairs)))

        if improved:
            message = "%s() got an unexpected keyword argument '%s'" % (
                func_name,
                unexpected
            )
        else:
            message = "'%s' is an invalid keyword argument for this function" % unexpected

        raise TooManyArguments(
            TypeError(message)
        )

    unassigned = num_args - len(
        [
            arg
            for arg in args
            if isAssigned(arg)
        ]
    )

    if unassigned:
        num_required = num_args - num_defaults

        if num_required > 0 or improved:
            if num_defaults == 0 and num_args != 1:
                raise TooManyArguments(
                    TypeError(
                        "%s expected %d arguments, got %d" % (
                            func_name,
                            num_args,
                            num_total
                        )
                    )
                )

            if num_required == 1:
                arg_desc = "1 argument" if python_version < 350 else "one argument"
            else:
                arg_desc = "%d arguments" % num_required

            raise TooManyArguments(
                TypeError(
                    "%s() takes %s %s (%d given)" % (
                        func_name,
                        "at least" if num_defaults > 0 else "exactly",
                        arg_desc,
                        num_total
                    )
                )
            )
        else:
            raise TooManyArguments(
                TypeError(
                    "%s expected %s%s, got %d" % (
                        func_name,
                        ( "at least " if python_version < 300 else "" )
                            if num_defaults > 0
                        else "exactly ",
                        "%d arguments" % num_required,
                        num_total
                    )
                )
            )

    return result
dataset/ETHPy150Open kayhayen/Nuitka/nuitka/nodes/ParameterSpecs.py/matchCall