diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 58c6f083..6f294ff7 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -52,7 +52,7 @@ class MergedExecutedParams(object): @debug.increase_indent -def search_params(evaluator, parent_context, funcdef): +def search_params(evaluator, execution_context, funcdef): """ A dynamic search for param values. If you try to complete a type: @@ -71,7 +71,7 @@ def search_params(evaluator, parent_context, funcdef): evaluator.dynamic_params_depth += 1 try: debug.dbg('Dynamic param search in %s.', funcdef.name.value, color='MAGENTA') - module_context = parent_context.get_root_context() + module_context = execution_context.get_root_context() function_executions = _search_function_executions( evaluator, module_context, @@ -85,7 +85,7 @@ def search_params(evaluator, parent_context, funcdef): params = [MergedExecutedParams(executed_params) for executed_params in zipped_params] # Evaluate the ExecutedParams to types. else: - params = [create_default_param(parent_context, p) for p in funcdef.params] + params = [create_default_param(execution_context, p) for p in funcdef.params] debug.dbg('Dynamic param result finished', color='MAGENTA') return params finally: diff --git a/jedi/evaluate/instance.py b/jedi/evaluate/instance.py index 5a41d86f..d0cd812a 100644 --- a/jedi/evaluate/instance.py +++ b/jedi/evaluate/instance.py @@ -383,14 +383,14 @@ class ParamArguments(object): def infer(self): return self._param.infer() - def __init__(self, class_context, funcdef): - self._class_context = class_context + def __init__(self, execution_context, funcdef): + self._execution_context = execution_context self._funcdef = funcdef def unpack(self, func=None): params = search_params( - self._class_context.evaluator, - self._class_context, + self._execution_context.evaluator, + self._execution_context, self._funcdef ) is_first = True @@ -403,8 +403,8 @@ class ParamArguments(object): class InstanceVarArgs(object): - def __init__(self, instance, funcdef, var_args): - self._instance = instance + def __init__(self, execution_context, funcdef, var_args): + self._execution_context = execution_context self._funcdef = funcdef self._var_args = var_args @@ -412,12 +412,12 @@ class InstanceVarArgs(object): def _get_var_args(self): if self._var_args is None: # TODO this parent_context might be wrong. test?! - return ParamArguments(self._instance.class_context, self._funcdef) + return ParamArguments(self._execution_context, self._funcdef) return self._var_args def unpack(self, func=None): - yield None, LazyKnownContext(self._instance) + yield None, LazyKnownContext(self._execution_context.instance) for values in self._get_var_args().unpack(func): yield values @@ -431,7 +431,7 @@ class InstanceVarArgs(object): class InstanceFunctionExecution(er.FunctionExecutionContext): def __init__(self, instance, parent_context, function_context, var_args): self.instance = instance - var_args = InstanceVarArgs(instance, function_context.tree_node, var_args) + var_args = InstanceVarArgs(self, function_context.tree_node, var_args) super(InstanceFunctionExecution, self).__init__( instance.evaluator, parent_context, function_context, var_args) diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index 6cb98951..ef1bcf79 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -61,7 +61,7 @@ class AbstractArguments(): raise ValueError yield values - def eval_all(self, func=None): + def eval_all(self, funcdef=None): """ Evaluates all arguments as a support for static analysis (normally Jedi). @@ -110,12 +110,12 @@ class TreeArguments(AbstractArguments): else: yield 0, child - def unpack(self, func=None): + def unpack(self, funcdef=None): named_args = [] for star_count, el in self._split(): if star_count == 1: arrays = self.context.eval_node(el) - iterators = [_iterate_star_args(self.context, a, el, func) + iterators = [_iterate_star_args(self.context, a, el, funcdef) for a in arrays] iterators = list(iterators) for values in list(zip_longest(*iterators)): @@ -127,7 +127,7 @@ class TreeArguments(AbstractArguments): elif star_count == 2: arrays = self._evaluator.eval_element(self.context, el) for dct in arrays: - for key, values in _star_star_dict(self.context, dct, el, func): + for key, values in _star_star_dict(self.context, dct, el, funcdef): yield key, values else: if el.type == 'argument': @@ -195,7 +195,7 @@ class ValuesArguments(AbstractArguments): def __init__(self, values_list): self._values_list = values_list - def unpack(self, func=None): + def unpack(self, funcdef=None): for values in self._values_list: yield None, context.LazyKnownContexts(values) @@ -208,16 +208,16 @@ class ValuesArguments(AbstractArguments): class ExecutedParam(object): """Fake a param and give it values.""" - def __init__(self, var_args_context, original_param, var_args, lazy_context): - self._root_context = var_args_context.get_root_context() - self._original_param = original_param - self.var_args = var_args + def __init__(self, execution_context, param_node, lazy_context): + self._execution_context = execution_context + self._param_node = param_node self._lazy_context = lazy_context - self.string_name = self._original_param.name.value + self.string_name = param_node.name.value def infer(self): - pep0484_hints = pep0484.infer_param(self._root_context, self._original_param) - doc_params = docstrings.infer_param(self._root_context, self._original_param) + root_context = self._execution_context.get_root_context() + pep0484_hints = pep0484.infer_param(root_context, self._param_node) + doc_params = docstrings.infer_param(root_context, self._param_node) if pep0484_hints or doc_params: return list(set(pep0484_hints) | set(doc_params)) @@ -226,25 +226,32 @@ class ExecutedParam(object): @property def position_nr(self): # Need to use the original logic here, because it uses the parent. - return self._original_param.position_nr + return self._param_node.position_nr + + @property + def var_args(self): + return self._execution_context.var_args def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self.string_name) -def get_params(evaluator, parent_context, func, var_args): +def get_params(execution_context, var_args): result_params = [] param_dict = {} - for param in func.params: + 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(func)) + 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 func.params: + 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 @@ -260,12 +267,12 @@ def get_params(evaluator, parent_context, func, var_args): if key in keys_used: had_multiple_value_error = True m = ("TypeError: %s() got multiple values for keyword argument '%s'." - % (func.name, key)) + % (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(parent_context, key_param, var_args, argument) + keys_used[key] = ExecutedParam(execution_context, key_param, argument) key, argument = next(var_arg_iterator, (None, None)) try: @@ -285,11 +292,11 @@ def get_params(evaluator, parent_context, func, var_args): var_arg_iterator.push_back((key, argument)) break lazy_context_list.append(argument) - seq = iterable.FakeSequence(evaluator, 'tuple', lazy_context_list) + 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(evaluator, dict(non_matching_keys)) + dct = iterable.FakeDict(execution_context.evaluator, dict(non_matching_keys)) result_arg = context.LazyKnownContext(dct) non_matching_keys = {} else: @@ -300,7 +307,7 @@ def get_params(evaluator, parent_context, func, var_args): result_arg = context.LazyUnknownContext() if not keys_only: for node in var_args.get_calling_nodes(): - m = _error_argument_count(func, len(unpacked_va)) + m = _error_argument_count(funcdef, len(unpacked_va)) analysis.add(parent_context, 'type-error-too-few-arguments', node, message=m) else: @@ -308,7 +315,7 @@ def get_params(evaluator, parent_context, func, var_args): else: result_arg = argument - result_params.append(ExecutedParam(parent_context, param, var_args, result_arg)) + result_params.append(ExecutedParam(execution_context, param, result_arg)) if not isinstance(result_arg, context.LazyUnknownContext): keys_used[param.name.value] = result_params[-1] @@ -323,13 +330,13 @@ def get_params(evaluator, parent_context, func, var_args): 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(func, len(unpacked_va)) + 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'." \ - % (func.name, key) + % (funcdef.name, key) add_argument_issue( parent_context, 'type-error-keyword-argument', @@ -339,7 +346,7 @@ def get_params(evaluator, parent_context, func, var_args): remaining_arguments = list(var_arg_iterator) if remaining_arguments: - m = _error_argument_count(func, len(unpacked_va)) + 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] @@ -349,21 +356,21 @@ def get_params(evaluator, parent_context, func, var_args): return result_params -def _iterate_star_args(context, array, input_node, func=None): +def _iterate_star_args(context, array, input_node, funcdef=None): try: iter_ = array.py__iter__ except AttributeError: - if func is not None: - # TODO this func should not be needed. + if funcdef is not None: + # TODO this funcdef should not be needed. m = "TypeError: %s() argument after * must be a sequence, not %s" \ - % (func.name.value, array) + % (funcdef.name.value, array) analysis.add(context, 'type-error-star', input_node, message=m) else: for lazy_context in iter_(): yield lazy_context -def _star_star_dict(context, array, input_node, func): +def _star_star_dict(context, array, input_node, funcdef): from jedi.evaluate.instance import CompiledInstance if isinstance(array, CompiledInstance) and array.name.string_name == 'dict': # For now ignore this case. In the future add proper iterators and just @@ -372,35 +379,35 @@ def _star_star_dict(context, array, input_node, func): elif isinstance(array, iterable.AbstractSequence) and array.array_type == 'dict': return array.exact_key_items() else: - if func is not None: + if funcdef is not None: m = "TypeError: %s argument after ** must be a mapping, not %s" \ - % (func.name.value, array) + % (funcdef.name.value, array) analysis.add(context, 'type-error-star-star', input_node, message=m) return {} -def _error_argument_count(func, actual_count): - default_arguments = sum(1 for p in func.params if p.default or p.star_count) +def _error_argument_count(funcdef, actual_count): + default_arguments = sum(1 for p in funcdef.params if p.default or p.star_count) if default_arguments == 0: before = 'exactly ' else: - before = 'from %s to ' % (len(func.params) - default_arguments) + before = 'from %s to ' % (len(funcdef.params) - default_arguments) return ('TypeError: %s() takes %s%s arguments (%s given).' - % (func.name, before, len(func.params), actual_count)) + % (funcdef.name, before, len(funcdef.params), actual_count)) -def create_default_param(parent_context, param): +def create_default_param(execution_context, param): if param.star_count == 1: result_arg = context.LazyKnownContext( - iterable.FakeSequence(parent_context.evaluator, 'tuple', []) + iterable.FakeSequence(execution_context.evaluator, 'tuple', []) ) elif param.star_count == 2: result_arg = context.LazyKnownContext( - iterable.FakeDict(parent_context.evaluator, {}) + iterable.FakeDict(execution_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) + result_arg = context.LazyTreeContext(execution_context.parent_context, param.default) + return ExecutedParam(execution_context, param, result_arg) diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 322ce723..ed0e5934 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -412,7 +412,7 @@ class FunctionExecutionContext(context.TreeContext): @memoize_default(default=NO_DEFAULT) def get_params(self): - return param.get_params(self.evaluator, self.parent_context, self.tree_node, self.var_args) + return param.get_params(self, self.var_args) class AnonymousFunctionExecution(FunctionExecutionContext): @@ -423,7 +423,7 @@ class AnonymousFunctionExecution(FunctionExecutionContext): @memoize_default(default=NO_DEFAULT) def get_params(self): # We need to do a dynamic search here. - return search_params(self.evaluator, self.parent_context, self.tree_node) + return search_params(self.evaluator, self, self.tree_node) class ModuleAttributeName(AbstractNameDefinition):