def create_default_param(parent_context, param): if param.stars == 1: result_arg = context.LazyKnownContext( iterable.FakeSequence(parent_context.evaluator, 'tuple', [])) elif param.stars == 2: result_arg = context.LazyKnownContext( iterable.FakeDict(parent_context.evaluator, {})) elif param.default is None: result_arg = context.LazyUnknownContext() else: result_arg = context.LazyTreeContext(parent_context, param.default) return ExecutedParam(parent_context, param, None, result_arg)
def get_params(execution_context, var_args): result_params = [] param_dict = {} funcdef = execution_context.tree_node parent_context = execution_context.parent_context for param in funcdef.params: param_dict[param.name.value] = param unpacked_va = list(var_args.unpack(funcdef)) var_arg_iterator = common.PushBackIterator(iter(unpacked_va)) non_matching_keys = defaultdict(lambda: []) keys_used = {} keys_only = False had_multiple_value_error = False for param in funcdef.params: # The value and key can both be null. There, the defaults apply. # args / kwargs will just be empty arrays / dicts, respectively. # Wrong value count is just ignored. If you try to test cases that are # not allowed in Python, Jedi will maybe not show any completions. key, argument = next(var_arg_iterator, (None, None)) while key is not None: keys_only = True try: key_param = param_dict[key] except KeyError: non_matching_keys[key] = argument else: if key in keys_used: had_multiple_value_error = True m = ("TypeError: %s() got multiple values for keyword argument '%s'." % (funcdef.name, key)) for node in var_args.get_calling_nodes(): analysis.add(parent_context, 'type-error-multiple-values', node, message=m) else: keys_used[key] = ExecutedParam(execution_context, key_param, argument) key, argument = next(var_arg_iterator, (None, None)) try: result_params.append(keys_used[param.name.value]) continue except KeyError: pass if param.star_count == 1: # *args param lazy_context_list = [] if argument is not None: lazy_context_list.append(argument) for key, argument in var_arg_iterator: # Iterate until a key argument is found. if key: var_arg_iterator.push_back((key, argument)) break lazy_context_list.append(argument) seq = iterable.FakeSequence(execution_context.evaluator, 'tuple', lazy_context_list) result_arg = context.LazyKnownContext(seq) elif param.star_count == 2: # **kwargs param dct = iterable.FakeDict(execution_context.evaluator, dict(non_matching_keys)) result_arg = context.LazyKnownContext(dct) non_matching_keys = {} else: # normal param if argument is None: # No value: Return an empty container if param.default is None: result_arg = context.LazyUnknownContext() if not keys_only: for node in var_args.get_calling_nodes(): m = _error_argument_count(funcdef, len(unpacked_va)) analysis.add(parent_context, 'type-error-too-few-arguments', node, message=m) else: result_arg = context.LazyTreeContext(parent_context, param.default) else: result_arg = argument result_params.append(ExecutedParam(execution_context, param, result_arg)) if not isinstance(result_arg, context.LazyUnknownContext): keys_used[param.name.value] = result_params[-1] if keys_only: # All arguments should be handed over to the next function. It's not # about the values inside, it's about the names. Jedi needs to now that # there's nothing to find for certain names. for k in set(param_dict) - set(keys_used): param = param_dict[k] if not (non_matching_keys or had_multiple_value_error or param.star_count or param.default): # add a warning only if there's not another one. for node in var_args.get_calling_nodes(): m = _error_argument_count(funcdef, len(unpacked_va)) analysis.add(parent_context, 'type-error-too-few-arguments', node, message=m) for key, lazy_context in non_matching_keys.items(): m = "TypeError: %s() got an unexpected keyword argument '%s'." \ % (funcdef.name, key) add_argument_issue( parent_context, 'type-error-keyword-argument', lazy_context, message=m ) remaining_arguments = list(var_arg_iterator) if remaining_arguments: m = _error_argument_count(funcdef, len(unpacked_va)) # Just report an error for the first param that is not needed (like # cPython). first_key, lazy_context = remaining_arguments[0] if var_args.get_calling_nodes(): # There might not be a valid calling node so check for that first. add_argument_issue(parent_context, 'type-error-too-many-arguments', lazy_context, message=m) return result_params
def get_params(evaluator, func, var_args): param_names = [] param_dict = {} for param in func.params: param_dict[str(param.get_name())] = param unpacked_va = list(var_args.unpack(func)) from jedi.evaluate.representation import InstanceElement if isinstance(func, InstanceElement): # Include self at this place. unpacked_va.insert( 0, (None, [iterable.AlreadyEvaluated([func.instance])])) var_arg_iterator = common.PushBackIterator(iter(unpacked_va)) non_matching_keys = defaultdict(lambda: []) keys_used = {} keys_only = False had_multiple_value_error = False for param in func.params: # The value and key can both be null. There, the defaults apply. # args / kwargs will just be empty arrays / dicts, respectively. # Wrong value count is just ignored. If you try to test cases that are # not allowed in Python, Jedi will maybe not show any completions. default = [] if param.default is None else [param.default] key, va_values = next(var_arg_iterator, (None, default)) while key is not None: keys_only = True k = unicode(key) try: key_param = param_dict[unicode(key)] except KeyError: non_matching_keys[key] += va_values else: param_names.append( ExecutedParam(key_param, var_args, va_values).name) if k in keys_used: had_multiple_value_error = True m = ( "TypeError: %s() got multiple values for keyword argument '%s'." % (func.name, k)) calling_va = _get_calling_var_args(evaluator, var_args) if calling_va is not None: analysis.add(evaluator, 'type-error-multiple-values', calling_va, message=m) else: try: keys_used[k] = param_names[-1] except IndexError: # TODO this is wrong stupid and whatever. pass key, va_values = next(var_arg_iterator, (None, ())) values = [] if param.stars == 1: # *args param lst_values = [iterable.MergedNodes(va_values)] if va_values else [] for key, va_values in var_arg_iterator: # Iterate until a key argument is found. if key: var_arg_iterator.push_back((key, va_values)) break if va_values: lst_values.append(iterable.MergedNodes(va_values)) seq = iterable.FakeSequence(evaluator, lst_values, 'tuple') values = [iterable.AlreadyEvaluated([seq])] elif param.stars == 2: # **kwargs param dct = iterable.FakeDict(evaluator, dict(non_matching_keys)) values = [iterable.AlreadyEvaluated([dct])] non_matching_keys = {} else: # normal param if va_values: values = va_values else: # No value: Return an empty container values = [] if not keys_only: calling_va = var_args.get_calling_var_args() if calling_va is not None: m = _error_argument_count(func, len(unpacked_va)) analysis.add(evaluator, 'type-error-too-few-arguments', calling_va, message=m) # Now add to result if it's not one of the previously covered cases. if (not keys_only or param.stars == 2): param_names.append(ExecutedParam(param, var_args, values).name) keys_used[unicode(param.get_name())] = param_names[-1] if keys_only: # All arguments should be handed over to the next function. It's not # about the values inside, it's about the names. Jedi needs to now that # there's nothing to find for certain names. for k in set(param_dict) - set(keys_used): param = param_dict[k] values = [] if param.default is None else [param.default] param_names.append(ExecutedParam(param, var_args, values).name) if not (non_matching_keys or had_multiple_value_error or param.stars or param.default): # add a warning only if there's not another one. calling_va = _get_calling_var_args(evaluator, var_args) if calling_va is not None: m = _error_argument_count(func, len(unpacked_va)) analysis.add(evaluator, 'type-error-too-few-arguments', calling_va, message=m) for key, va_values in non_matching_keys.items(): m = "TypeError: %s() got an unexpected keyword argument '%s'." \ % (func.name, key) for value in va_values: analysis.add(evaluator, 'type-error-keyword-argument', value.parent, message=m) remaining_params = list(var_arg_iterator) if remaining_params: m = _error_argument_count(func, len(unpacked_va)) # Just report an error for the first param that is not needed (like # cPython). first_key, first_values = remaining_params[0] for v in first_values: if first_key is not None: # Is a keyword argument, return the whole thing instead of just # the value node. v = v.parent try: non_kw_param = keys_used[first_key] except KeyError: pass else: origin_args = non_kw_param.parent.var_args.argument_node # TODO calculate the var_args tree and check if it's in # the tree (if not continue). # print('\t\tnonkw', non_kw_param.parent.var_args.argument_node, ) if origin_args not in [ f.parent.parent for f in first_values ]: continue analysis.add(evaluator, 'type-error-too-many-arguments', v, message=m) return param_names