forked from VimPlug/jedi
Give ExecutionParams a better way of knowing what called them.
This commit is contained in:
@@ -52,7 +52,7 @@ class MergedExecutedParams(object):
|
|||||||
|
|
||||||
|
|
||||||
@debug.increase_indent
|
@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:
|
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
|
evaluator.dynamic_params_depth += 1
|
||||||
try:
|
try:
|
||||||
debug.dbg('Dynamic param search in %s.', funcdef.name.value, color='MAGENTA')
|
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(
|
function_executions = _search_function_executions(
|
||||||
evaluator,
|
evaluator,
|
||||||
module_context,
|
module_context,
|
||||||
@@ -85,7 +85,7 @@ def search_params(evaluator, parent_context, funcdef):
|
|||||||
params = [MergedExecutedParams(executed_params) for executed_params in zipped_params]
|
params = [MergedExecutedParams(executed_params) for executed_params in zipped_params]
|
||||||
# Evaluate the ExecutedParams to types.
|
# Evaluate the ExecutedParams to types.
|
||||||
else:
|
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')
|
debug.dbg('Dynamic param result finished', color='MAGENTA')
|
||||||
return params
|
return params
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -383,14 +383,14 @@ class ParamArguments(object):
|
|||||||
def infer(self):
|
def infer(self):
|
||||||
return self._param.infer()
|
return self._param.infer()
|
||||||
|
|
||||||
def __init__(self, class_context, funcdef):
|
def __init__(self, execution_context, funcdef):
|
||||||
self._class_context = class_context
|
self._execution_context = execution_context
|
||||||
self._funcdef = funcdef
|
self._funcdef = funcdef
|
||||||
|
|
||||||
def unpack(self, func=None):
|
def unpack(self, func=None):
|
||||||
params = search_params(
|
params = search_params(
|
||||||
self._class_context.evaluator,
|
self._execution_context.evaluator,
|
||||||
self._class_context,
|
self._execution_context,
|
||||||
self._funcdef
|
self._funcdef
|
||||||
)
|
)
|
||||||
is_first = True
|
is_first = True
|
||||||
@@ -403,8 +403,8 @@ class ParamArguments(object):
|
|||||||
|
|
||||||
|
|
||||||
class InstanceVarArgs(object):
|
class InstanceVarArgs(object):
|
||||||
def __init__(self, instance, funcdef, var_args):
|
def __init__(self, execution_context, funcdef, var_args):
|
||||||
self._instance = instance
|
self._execution_context = execution_context
|
||||||
self._funcdef = funcdef
|
self._funcdef = funcdef
|
||||||
self._var_args = var_args
|
self._var_args = var_args
|
||||||
|
|
||||||
@@ -412,12 +412,12 @@ class InstanceVarArgs(object):
|
|||||||
def _get_var_args(self):
|
def _get_var_args(self):
|
||||||
if self._var_args is None:
|
if self._var_args is None:
|
||||||
# TODO this parent_context might be wrong. test?!
|
# 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
|
return self._var_args
|
||||||
|
|
||||||
def unpack(self, func=None):
|
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):
|
for values in self._get_var_args().unpack(func):
|
||||||
yield values
|
yield values
|
||||||
|
|
||||||
@@ -431,7 +431,7 @@ class InstanceVarArgs(object):
|
|||||||
class InstanceFunctionExecution(er.FunctionExecutionContext):
|
class InstanceFunctionExecution(er.FunctionExecutionContext):
|
||||||
def __init__(self, instance, parent_context, function_context, var_args):
|
def __init__(self, instance, parent_context, function_context, var_args):
|
||||||
self.instance = instance
|
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__(
|
super(InstanceFunctionExecution, self).__init__(
|
||||||
instance.evaluator, parent_context, function_context, var_args)
|
instance.evaluator, parent_context, function_context, var_args)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class AbstractArguments():
|
|||||||
raise ValueError
|
raise ValueError
|
||||||
yield values
|
yield values
|
||||||
|
|
||||||
def eval_all(self, func=None):
|
def eval_all(self, funcdef=None):
|
||||||
"""
|
"""
|
||||||
Evaluates all arguments as a support for static analysis
|
Evaluates all arguments as a support for static analysis
|
||||||
(normally Jedi).
|
(normally Jedi).
|
||||||
@@ -110,12 +110,12 @@ class TreeArguments(AbstractArguments):
|
|||||||
else:
|
else:
|
||||||
yield 0, child
|
yield 0, child
|
||||||
|
|
||||||
def unpack(self, func=None):
|
def unpack(self, funcdef=None):
|
||||||
named_args = []
|
named_args = []
|
||||||
for star_count, el in self._split():
|
for star_count, el in self._split():
|
||||||
if star_count == 1:
|
if star_count == 1:
|
||||||
arrays = self.context.eval_node(el)
|
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]
|
for a in arrays]
|
||||||
iterators = list(iterators)
|
iterators = list(iterators)
|
||||||
for values in list(zip_longest(*iterators)):
|
for values in list(zip_longest(*iterators)):
|
||||||
@@ -127,7 +127,7 @@ class TreeArguments(AbstractArguments):
|
|||||||
elif star_count == 2:
|
elif star_count == 2:
|
||||||
arrays = self._evaluator.eval_element(self.context, el)
|
arrays = self._evaluator.eval_element(self.context, el)
|
||||||
for dct in arrays:
|
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
|
yield key, values
|
||||||
else:
|
else:
|
||||||
if el.type == 'argument':
|
if el.type == 'argument':
|
||||||
@@ -195,7 +195,7 @@ class ValuesArguments(AbstractArguments):
|
|||||||
def __init__(self, values_list):
|
def __init__(self, values_list):
|
||||||
self._values_list = values_list
|
self._values_list = values_list
|
||||||
|
|
||||||
def unpack(self, func=None):
|
def unpack(self, funcdef=None):
|
||||||
for values in self._values_list:
|
for values in self._values_list:
|
||||||
yield None, context.LazyKnownContexts(values)
|
yield None, context.LazyKnownContexts(values)
|
||||||
|
|
||||||
@@ -208,16 +208,16 @@ class ValuesArguments(AbstractArguments):
|
|||||||
|
|
||||||
class ExecutedParam(object):
|
class ExecutedParam(object):
|
||||||
"""Fake a param and give it values."""
|
"""Fake a param and give it values."""
|
||||||
def __init__(self, var_args_context, original_param, var_args, lazy_context):
|
def __init__(self, execution_context, param_node, lazy_context):
|
||||||
self._root_context = var_args_context.get_root_context()
|
self._execution_context = execution_context
|
||||||
self._original_param = original_param
|
self._param_node = param_node
|
||||||
self.var_args = var_args
|
|
||||||
self._lazy_context = lazy_context
|
self._lazy_context = lazy_context
|
||||||
self.string_name = self._original_param.name.value
|
self.string_name = param_node.name.value
|
||||||
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
pep0484_hints = pep0484.infer_param(self._root_context, self._original_param)
|
root_context = self._execution_context.get_root_context()
|
||||||
doc_params = docstrings.infer_param(self._root_context, self._original_param)
|
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:
|
if pep0484_hints or doc_params:
|
||||||
return list(set(pep0484_hints) | set(doc_params))
|
return list(set(pep0484_hints) | set(doc_params))
|
||||||
|
|
||||||
@@ -226,25 +226,32 @@ class ExecutedParam(object):
|
|||||||
@property
|
@property
|
||||||
def position_nr(self):
|
def position_nr(self):
|
||||||
# Need to use the original logic here, because it uses the parent.
|
# 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):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (self.__class__.__name__, self.string_name)
|
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 = []
|
result_params = []
|
||||||
param_dict = {}
|
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
|
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))
|
var_arg_iterator = common.PushBackIterator(iter(unpacked_va))
|
||||||
|
|
||||||
non_matching_keys = defaultdict(lambda: [])
|
non_matching_keys = defaultdict(lambda: [])
|
||||||
keys_used = {}
|
keys_used = {}
|
||||||
keys_only = False
|
keys_only = False
|
||||||
had_multiple_value_error = 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.
|
# The value and key can both be null. There, the defaults apply.
|
||||||
# args / kwargs will just be empty arrays / dicts, respectively.
|
# args / kwargs will just be empty arrays / dicts, respectively.
|
||||||
# Wrong value count is just ignored. If you try to test cases that are
|
# 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:
|
if key in keys_used:
|
||||||
had_multiple_value_error = True
|
had_multiple_value_error = True
|
||||||
m = ("TypeError: %s() got multiple values for keyword argument '%s'."
|
m = ("TypeError: %s() got multiple values for keyword argument '%s'."
|
||||||
% (func.name, key))
|
% (funcdef.name, key))
|
||||||
for node in var_args.get_calling_nodes():
|
for node in var_args.get_calling_nodes():
|
||||||
analysis.add(parent_context, 'type-error-multiple-values',
|
analysis.add(parent_context, 'type-error-multiple-values',
|
||||||
node, message=m)
|
node, message=m)
|
||||||
else:
|
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))
|
key, argument = next(var_arg_iterator, (None, None))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -285,11 +292,11 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
var_arg_iterator.push_back((key, argument))
|
var_arg_iterator.push_back((key, argument))
|
||||||
break
|
break
|
||||||
lazy_context_list.append(argument)
|
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)
|
result_arg = context.LazyKnownContext(seq)
|
||||||
elif param.star_count == 2:
|
elif param.star_count == 2:
|
||||||
# **kwargs param
|
# **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)
|
result_arg = context.LazyKnownContext(dct)
|
||||||
non_matching_keys = {}
|
non_matching_keys = {}
|
||||||
else:
|
else:
|
||||||
@@ -300,7 +307,7 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
result_arg = context.LazyUnknownContext()
|
result_arg = context.LazyUnknownContext()
|
||||||
if not keys_only:
|
if not keys_only:
|
||||||
for node in var_args.get_calling_nodes():
|
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',
|
analysis.add(parent_context, 'type-error-too-few-arguments',
|
||||||
node, message=m)
|
node, message=m)
|
||||||
else:
|
else:
|
||||||
@@ -308,7 +315,7 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
else:
|
else:
|
||||||
result_arg = argument
|
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):
|
if not isinstance(result_arg, context.LazyUnknownContext):
|
||||||
keys_used[param.name.value] = result_params[-1]
|
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):
|
param.star_count or param.default):
|
||||||
# add a warning only if there's not another one.
|
# add a warning only if there's not another one.
|
||||||
for node in var_args.get_calling_nodes():
|
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',
|
analysis.add(parent_context, 'type-error-too-few-arguments',
|
||||||
node, message=m)
|
node, message=m)
|
||||||
|
|
||||||
for key, lazy_context in non_matching_keys.items():
|
for key, lazy_context in non_matching_keys.items():
|
||||||
m = "TypeError: %s() got an unexpected keyword argument '%s'." \
|
m = "TypeError: %s() got an unexpected keyword argument '%s'." \
|
||||||
% (func.name, key)
|
% (funcdef.name, key)
|
||||||
add_argument_issue(
|
add_argument_issue(
|
||||||
parent_context,
|
parent_context,
|
||||||
'type-error-keyword-argument',
|
'type-error-keyword-argument',
|
||||||
@@ -339,7 +346,7 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
|
|
||||||
remaining_arguments = list(var_arg_iterator)
|
remaining_arguments = list(var_arg_iterator)
|
||||||
if remaining_arguments:
|
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
|
# Just report an error for the first param that is not needed (like
|
||||||
# cPython).
|
# cPython).
|
||||||
first_key, lazy_context = remaining_arguments[0]
|
first_key, lazy_context = remaining_arguments[0]
|
||||||
@@ -349,21 +356,21 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
return result_params
|
return result_params
|
||||||
|
|
||||||
|
|
||||||
def _iterate_star_args(context, array, input_node, func=None):
|
def _iterate_star_args(context, array, input_node, funcdef=None):
|
||||||
try:
|
try:
|
||||||
iter_ = array.py__iter__
|
iter_ = array.py__iter__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if func is not None:
|
if funcdef is not None:
|
||||||
# TODO this func should not be needed.
|
# TODO this funcdef should not be needed.
|
||||||
m = "TypeError: %s() argument after * must be a sequence, not %s" \
|
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)
|
analysis.add(context, 'type-error-star', input_node, message=m)
|
||||||
else:
|
else:
|
||||||
for lazy_context in iter_():
|
for lazy_context in iter_():
|
||||||
yield lazy_context
|
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
|
from jedi.evaluate.instance import CompiledInstance
|
||||||
if isinstance(array, CompiledInstance) and array.name.string_name == 'dict':
|
if isinstance(array, CompiledInstance) and array.name.string_name == 'dict':
|
||||||
# For now ignore this case. In the future add proper iterators and just
|
# 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':
|
elif isinstance(array, iterable.AbstractSequence) and array.array_type == 'dict':
|
||||||
return array.exact_key_items()
|
return array.exact_key_items()
|
||||||
else:
|
else:
|
||||||
if func is not None:
|
if funcdef is not None:
|
||||||
m = "TypeError: %s argument after ** must be a mapping, not %s" \
|
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)
|
analysis.add(context, 'type-error-star-star', input_node, message=m)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def _error_argument_count(func, actual_count):
|
def _error_argument_count(funcdef, actual_count):
|
||||||
default_arguments = sum(1 for p in func.params if p.default or p.star_count)
|
default_arguments = sum(1 for p in funcdef.params if p.default or p.star_count)
|
||||||
|
|
||||||
if default_arguments == 0:
|
if default_arguments == 0:
|
||||||
before = 'exactly '
|
before = 'exactly '
|
||||||
else:
|
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).'
|
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:
|
if param.star_count == 1:
|
||||||
result_arg = context.LazyKnownContext(
|
result_arg = context.LazyKnownContext(
|
||||||
iterable.FakeSequence(parent_context.evaluator, 'tuple', [])
|
iterable.FakeSequence(execution_context.evaluator, 'tuple', [])
|
||||||
)
|
)
|
||||||
elif param.star_count == 2:
|
elif param.star_count == 2:
|
||||||
result_arg = context.LazyKnownContext(
|
result_arg = context.LazyKnownContext(
|
||||||
iterable.FakeDict(parent_context.evaluator, {})
|
iterable.FakeDict(execution_context.evaluator, {})
|
||||||
)
|
)
|
||||||
elif param.default is None:
|
elif param.default is None:
|
||||||
result_arg = context.LazyUnknownContext()
|
result_arg = context.LazyUnknownContext()
|
||||||
else:
|
else:
|
||||||
result_arg = context.LazyTreeContext(parent_context, param.default)
|
result_arg = context.LazyTreeContext(execution_context.parent_context, param.default)
|
||||||
return ExecutedParam(parent_context, param, None, result_arg)
|
return ExecutedParam(execution_context, param, result_arg)
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ class FunctionExecutionContext(context.TreeContext):
|
|||||||
|
|
||||||
@memoize_default(default=NO_DEFAULT)
|
@memoize_default(default=NO_DEFAULT)
|
||||||
def get_params(self):
|
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):
|
class AnonymousFunctionExecution(FunctionExecutionContext):
|
||||||
@@ -423,7 +423,7 @@ class AnonymousFunctionExecution(FunctionExecutionContext):
|
|||||||
@memoize_default(default=NO_DEFAULT)
|
@memoize_default(default=NO_DEFAULT)
|
||||||
def get_params(self):
|
def get_params(self):
|
||||||
# We need to do a dynamic search here.
|
# 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):
|
class ModuleAttributeName(AbstractNameDefinition):
|
||||||
|
|||||||
Reference in New Issue
Block a user