diff --git a/jedi/evaluate/analysis.py b/jedi/evaluate/analysis.py index ded4e9f2..6261b5c8 100644 --- a/jedi/evaluate/analysis.py +++ b/jedi/evaluate/analysis.py @@ -86,9 +86,10 @@ def add(node_context, error_name, node, message=None, typ=Error, payload=None): # TODO this path is probably not right module_context = node_context.get_root_context() module_path = module_context.py__file__() - instance = typ(error_name, module_path, node.start_pos, message) - debug.warning(str(instance), format=False) - node_context.evaluator.analysis.append(instance) + issue_instance = typ(error_name, module_path, node.start_pos, message) + debug.warning(str(issue_instance), format=False) + node_context.evaluator.analysis.append(issue_instance) + return issue_instance def _check_for_setattr(instance): diff --git a/jedi/evaluate/arguments.py b/jedi/evaluate/arguments.py index ed49d514..6faae67d 100644 --- a/jedi/evaluate/arguments.py +++ b/jedi/evaluate/arguments.py @@ -11,7 +11,7 @@ from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts, \ from jedi.evaluate.filters import ParamName from jedi.evaluate.base_context import NO_CONTEXTS, ContextSet from jedi.evaluate.context import iterable -from jedi.evaluate.param import get_executed_params, ExecutedParam +from jedi.evaluate.param import get_executed_params_and_issues, ExecutedParam def try_iter_content(types, depth=0): @@ -148,12 +148,12 @@ class AbstractArguments(object): def unpack(self, funcdef=None): raise NotImplementedError - def get_executed_params(self, execution_context): - return get_executed_params(execution_context, self) + def get_executed_params_and_issues(self, execution_context): + return get_executed_params_and_issues(execution_context, self) class AnonymousArguments(AbstractArguments): - def get_executed_params(self, execution_context): + def get_executed_params_and_issues(self, execution_context): from jedi.evaluate.dynamic import search_params return search_params( execution_context.evaluator, diff --git a/jedi/evaluate/context/function.py b/jedi/evaluate/context/function.py index cfaca4ae..8eded724 100644 --- a/jedi/evaluate/context/function.py +++ b/jedi/evaluate/context/function.py @@ -106,7 +106,7 @@ class FunctionContext(use_metaclass(CachedMetaClass, AbstractFunction)): if overloaded_funcs: return OverloadedFunctionContext( function, - ContextSet.from_iterable(create(f) for f in overloaded_funcs) + [create(f) for f in overloaded_funcs] ) return function @@ -273,12 +273,16 @@ class FunctionExecutionContext(TreeContext): origin_scope=origin_scope) @evaluator_method_cache() - def get_executed_params(self): - return self.var_args.get_executed_params(self) + def get_executed_params_and_issues(self): + return self.var_args.get_executed_params_and_issues(self) def matches_signature(self): + executed_params, issues = self.get_executed_params_and_issues() + if issues: + return False + matches = all(executed_param.matches_signature() - for executed_param in self.get_executed_params()) + for executed_param in executed_params) if debug.enable_notice: signature = parser_utils.get_call_signature(self.tree_node) if matches: diff --git a/jedi/evaluate/context/instance.py b/jedi/evaluate/context/instance.py index 6d16e270..d8827489 100644 --- a/jedi/evaluate/context/instance.py +++ b/jedi/evaluate/context/instance.py @@ -32,11 +32,11 @@ class AnonymousInstanceArguments(AnonymousArguments): def __init__(self, instance): self._instance = instance - def get_executed_params(self, execution_context): + def get_executed_params_and_issues(self, execution_context): from jedi.evaluate.dynamic import search_params tree_params = execution_context.tree_node.get_params() if not tree_params: - return [] + return [], [] self_param = InstanceExecutedParam(self._instance, tree_params[0]) if len(tree_params) == 1: @@ -49,7 +49,7 @@ class AnonymousInstanceArguments(AnonymousArguments): execution_context.tree_node )) executed_params[0] = self_param - return executed_params + return [], executed_params class AbstractInstanceContext(Context): @@ -273,7 +273,6 @@ class TreeInstance(AbstractInstanceContext): if not execution.matches_signature(): # First check if the signature even matches, if not we don't # need to infer anything. - print('no m', bound) continue print(bound) context_set = define_type_vars_for_execution( @@ -541,11 +540,11 @@ class InstanceArguments(AbstractArguments): def get_calling_nodes(self): return self._arguments.get_calling_nodes() - def get_executed_params(self, execution_context): + def get_executed_params_and_issues(self, execution_context): if isinstance(self._arguments, AnonymousInstanceArguments): - return self._arguments.get_executed_params(execution_context) + return self._arguments.get_executed_params_and_issues(execution_context) - return super(InstanceArguments, self).get_executed_params(execution_context) + return super(InstanceArguments, self).get_executed_params_and_issues(execution_context) def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self._arguments) diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 7f7b0d87..588f1be6 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -99,7 +99,7 @@ def search_params(evaluator, execution_context, funcdef): ) if function_executions: zipped_params = zip(*list( - function_execution.get_executed_params() + function_execution.get_executed_params_and_issues()[0] for function_execution in function_executions )) params = [DynamicExecutedParams(evaluator, executed_params) for executed_params in zipped_params] @@ -208,7 +208,7 @@ def _check_name_for_execution(evaluator, context, compare_node, name, trailer): # Here we're trying to find decorators by checking the first # parameter. It's not very generic though. Should find a better # solution that also applies to nested decorators. - params = value.parent_context.get_executed_params() + params, _ = value.parent_context.get_executed_params_and_issues() if len(params) != 1: continue values = params[0].infer() diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py index e60254b2..841bc975 100644 --- a/jedi/evaluate/filters.py +++ b/jedi/evaluate/filters.py @@ -136,7 +136,7 @@ class ParamName(AbstractTreeName): return self.get_param().infer() def get_param(self): - params = self.parent_context.get_executed_params() + params, _ = self.parent_context.get_executed_params_and_issues() param_node = search_ancestor(self.tree_name, 'param') return params[param_node.position_index] diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index b8514583..65bd71e3 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -13,7 +13,7 @@ def _add_argument_issue(parent_context, error_name, lazy_context, message): node = lazy_context.data if node.parent.type == 'argument': node = node.parent - analysis.add(parent_context, error_name, node, message) + return analysis.add(parent_context, error_name, node, message) class ExecutedParam(object): @@ -58,7 +58,25 @@ class ExecutedParam(object): return '<%s: %s>' % (self.__class__.__name__, self.string_name) -def get_executed_params(execution_context, var_args): +def get_executed_params_and_issues(execution_context, var_args): + def too_many_args(argument): + m = _error_argument_count(funcdef, len(unpacked_va)) + # Just report an error for the first param that is not needed (like + # cPython). + if var_args.get_calling_nodes(): + # There might not be a valid calling node so check for that first. + issues.append( + _add_argument_issue( + default_param_context, + 'type-error-too-many-arguments', + lazy_context, + message=m + ) + ) + else: + issues.append(None) + + issues = [] # List[Optional[analysis issue]] result_params = [] param_dict = {} funcdef = execution_context.tree_node @@ -94,8 +112,10 @@ def get_executed_params(execution_context, var_args): m = ("TypeError: %s() got multiple values for keyword argument '%s'." % (funcdef.name, key)) for node in var_args.get_calling_nodes(): - analysis.add(default_param_context, 'type-error-multiple-values', - node, message=m) + issues.append( + analysis.add(default_param_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)) @@ -120,6 +140,8 @@ def get_executed_params(execution_context, var_args): seq = iterable.FakeSequence(execution_context.evaluator, u'tuple', lazy_context_list) result_arg = LazyKnownContext(seq) elif param.star_count == 2: + if argument is not None: + too_many_args(argument) # **kwargs param dct = iterable.FakeDict(execution_context.evaluator, dict(non_matching_keys)) result_arg = LazyKnownContext(dct) @@ -133,8 +155,14 @@ def get_executed_params(execution_context, var_args): if not keys_only: for node in var_args.get_calling_nodes(): m = _error_argument_count(funcdef, len(unpacked_va)) - analysis.add(default_param_context, 'type-error-too-few-arguments', - node, message=m) + issues.append( + analysis.add( + default_param_context, + 'type-error-too-few-arguments', + node, + message=m, + ) + ) else: result_arg = LazyTreeContext(default_param_context, param.default) else: @@ -156,34 +184,28 @@ def get_executed_params(execution_context, var_args): # 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(default_param_context, 'type-error-too-few-arguments', - node, message=m) + issues.append( + analysis.add(default_param_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( - default_param_context, - 'type-error-keyword-argument', - lazy_context, - message=m + issues.append( + _add_argument_issue( + default_param_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( - default_param_context, - 'type-error-too-many-arguments', - lazy_context, - message=m - ) - return result_params + too_many_args(lazy_context) + return result_params, issues def _error_argument_count(funcdef, actual_count): diff --git a/jedi/evaluate/pep0484.py b/jedi/evaluate/pep0484.py index 63cd9e60..2378f984 100644 --- a/jedi/evaluate/pep0484.py +++ b/jedi/evaluate/pep0484.py @@ -250,7 +250,8 @@ def _infer_type_vars_for_execution(execution_context, annotation_dict): context = execution_context.function_context.get_default_param_context() annotation_variable_results = {} - for executed_param in execution_context.get_executed_params(): + executed_params, _ = execution_context.get_executed_params_and_issues() + for executed_param in executed_params: try: annotation_node = annotation_dict[executed_param.string_name] except KeyError: