1
0
forked from VimPlug/jedi

Try to get star arguments working just a little bit.

This commit is contained in:
Dave Halter
2016-10-27 18:14:20 +02:00
parent bcaf06399f
commit a620c7dbdb
8 changed files with 191 additions and 161 deletions

View File

@@ -197,11 +197,6 @@ class Evaluator(object):
return types return types
def eval_element(self, context, element): def eval_element(self, context, element):
if isinstance(element, iterable.AlreadyEvaluated):
return set(element)
elif isinstance(element, iterable.MergedNodes):
return iterable.unite(self.eval_element(context, e) for e in element)
if_stmt = element.get_parent_until((tree.IfStmt, tree.ForStmt, tree.IsScope)) if_stmt = element.get_parent_until((tree.IfStmt, tree.ForStmt, tree.IsScope))
predefined_if_name_dict = self.predefined_if_name_dict_dict.get(if_stmt) predefined_if_name_dict = self.predefined_if_name_dict_dict.get(if_stmt)
if predefined_if_name_dict is None and isinstance(if_stmt, tree.IfStmt): if predefined_if_name_dict is None and isinstance(if_stmt, tree.IfStmt):
@@ -402,13 +397,13 @@ class Evaluator(object):
if trailer_op == '.': if trailer_op == '.':
new_types |= self.find_types(typ, node) new_types |= self.find_types(typ, node)
elif trailer_op == '(': elif trailer_op == '(':
arguments = param.Arguments(self, context, node, trailer) arguments = param.TreeArguments(self, context, node, trailer)
new_types |= self.execute(typ, arguments) new_types |= self.execute(typ, arguments)
return new_types return new_types
@debug.increase_indent @debug.increase_indent
def execute(self, obj, arguments=None): def execute(self, obj, arguments=None):
if not isinstance(arguments, param.Arguments): if not isinstance(arguments, param.AbstractArguments):
raise NotImplementedError raise NotImplementedError
arguments = param.Arguments(self, arguments) arguments = param.Arguments(self, arguments)

View File

@@ -18,15 +18,12 @@ class Context(object):
def execute(self, arguments=None): def execute(self, arguments=None):
return self._evaluator.execute(self, arguments) return self._evaluator.execute(self, arguments)
def execute_evaluated(self, *args): def execute_evaluated(self, *value_list):
""" """
Execute a function with already executed arguments. Execute a function with already executed arguments.
""" """
from jedi.evaluate.iterable import AlreadyEvaluated from jedi.evaluate.param import ValueArguments
from jedi.evaluate.param import Arguments return self.execute(ValueArguments(value_list))
# TODO UGLY
args = [AlreadyEvaluated([arg]) for arg in args]
return self.execute(Arguments(self._evaluator, self, args))
class TreeContext(Context): class TreeContext(Context):

View File

@@ -95,6 +95,8 @@ def search_function_call(evaluator, func):
# We have to remove decorators, because they are not the # We have to remove decorators, because they are not the
# "original" functions, this way we can easily compare. # "original" functions, this way we can easily compare.
# At the same time we also have to remove InstanceElements. # At the same time we also have to remove InstanceElements.
return typ
# TODO remove
if typ.isinstance(er.Function, er.Instance) \ if typ.isinstance(er.Function, er.Instance) \
and typ.decorates is not None: and typ.decorates is not None:
return typ.decorates return typ.decorates
@@ -129,9 +131,11 @@ def search_function_call(evaluator, func):
if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES: if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES:
return listener.param_possibilities return listener.param_possibilities
for typ in evaluator.goto_definitions(name): context = evaluator.create_context(name)
for typ in evaluator.goto_definitions(context, name):
undecorated = undecorate(typ) undecorated = undecorate(typ)
if evaluator.wrap(compare) == undecorated: # TODO really?
if evaluator.wrap(context, compare) == undecorated:
# Only if we have the correct function we execute # Only if we have the correct function we execute
# it, otherwise just ignore it. # it, otherwise just ignore it.
evaluator.eval_trailer([typ], trailer) evaluator.eval_trailer([typ], trailer)

View File

@@ -25,8 +25,8 @@ class AbstractNameDefinition():
def __repr__(self): def __repr__(self):
if self.start_pos is None: if self.start_pos is None:
return '<%s: %s>' % (type(self).__name__, self.string_name) return '<%s: %s>' % (self.__class__.__name__, self.string_name)
return '<%s: %s@%s>' % (type(self).__name__, self.string_name, self.start_pos) return '<%s: %s@%s>' % (self.__class__.__name__, self.string_name, self.start_pos)
def execute(self, arguments): def execute(self, arguments):
return unite(context.execute(arguments) for context in self.infer()) return unite(context.execute(arguments) for context in self.infer())

View File

@@ -470,7 +470,7 @@ def _eval_param(evaluator, context, param, scope):
typ = list(evaluator.find_types(evaluator.BUILTINS, t))[0] typ = list(evaluator.find_types(evaluator.BUILTINS, t))[0]
res_new = evaluator.execute(typ) res_new = evaluator.execute(typ)
if param.default: if param.default:
res_new |= evaluator.eval_element(param.default) res_new |= evaluator.eval_element(context, param.default)
return res_new return res_new

View File

@@ -35,7 +35,7 @@ from jedi.evaluate.filters import DictFilter
from jedi.evaluate.context import Context from jedi.evaluate.context import Context
class AbstractArrayContext(Context): class AbstractSequence(Context):
def get_filters(self, search_global, until_position=None, origin_scope=None): def get_filters(self, search_global, until_position=None, origin_scope=None):
raise NotImplementedError raise NotImplementedError
@@ -152,6 +152,7 @@ class Generator(use_metaclass(CachedMetaClass, IterableWrapper, GeneratorMixin))
return f.get_yield_types() return f.get_yield_types()
def __getattr__(self, name): def __getattr__(self, name):
raise NotImplementedError
if name not in ['start_pos', 'end_pos', 'parent', 'get_imports', if name not in ['start_pos', 'end_pos', 'parent', 'get_imports',
'doc', 'docstr', 'get_parent_until', 'doc', 'docstr', 'get_parent_until',
'get_code', 'subscopes']: 'get_code', 'subscopes']:
@@ -288,7 +289,6 @@ class ArrayMixin(object):
def _imitate_values(self): def _imitate_values(self):
items = self.dict_values() items = self.dict_values()
return create_evaluated_sequence_set(self._evaluator, items, sequence_type='list') return create_evaluated_sequence_set(self._evaluator, items, sequence_type='list')
#return set([FakeSequence(self._evaluator, [AlreadyEvaluated(items)], 'tuple')])
@register_builtin_method('items', type='dict') @register_builtin_method('items', type='dict')
def _imitate_items(self): def _imitate_items(self):
@@ -352,7 +352,7 @@ class GeneratorComprehension(Comprehension, GeneratorMixin):
pass pass
class ArrayLiteralContext(AbstractArrayContext, ArrayMixin): class ArrayLiteralContext(AbstractSequence, ArrayMixin):
mapping = {'(': 'tuple', mapping = {'(': 'tuple',
'[': 'list', '[': 'list',
'{': 'dict'} '{': 'dict'}
@@ -390,6 +390,7 @@ class ArrayLiteralContext(AbstractArrayContext, ArrayMixin):
return self.parent_context.eval_node(self._items()[index]) return self.parent_context.eval_node(self._items()[index])
def __getattr__(self, name): def __getattr__(self, name):
raise NotImplementedError
if name not in ['start_pos', 'get_only_subelement', 'parent', if name not in ['start_pos', 'get_only_subelement', 'parent',
'get_parent_until', 'items']: 'get_parent_until', 'items']:
raise AttributeError('Strange access on %s: %s.' % (self, name)) raise AttributeError('Strange access on %s: %s.' % (self, name))
@@ -474,15 +475,28 @@ class ImplicitTuple(_FakeArray):
class FakeSequence(_FakeArray): class FakeSequence(_FakeArray):
def __init__(self, evaluator, sequence_values, type): def __init__(self, evaluator, type, context_sets):
""" """
type should be one of "tuple", "list" type should be one of "tuple", "list"
""" """
super(FakeSequence, self).__init__(evaluator, sequence_values, type) super(FakeSequence, self).__init__(evaluator, context_sets, type)
self._sequence_values = sequence_values self._context_sets = context_sets
def _resolve(self, context_set):
for x in context_set:
try:
infer = x.infer
except AttributeError:
yield x
else:
for value in infer():
yield value
def _items(self): def _items(self):
return self._sequence_values return self._context_sets
def py__getitem__(self, index):
return set(self._resolve(self._context_sets[index]))
def create_evaluated_sequence_set(evaluator, *types_order, **kwargs): def create_evaluated_sequence_set(evaluator, *types_order, **kwargs):
@@ -499,12 +513,17 @@ def create_evaluated_sequence_set(evaluator, *types_order, **kwargs):
class AlreadyEvaluated(frozenset): class AlreadyEvaluated(frozenset):
"""A simple container to add already evaluated objects to an array.""" """A simple container to add already evaluated objects to an array."""
def __init__(self, *args, **kwargs):
raise DeprecationWarning
def get_code(self, normalized=False): def get_code(self, normalized=False):
# For debugging purposes. # For debugging purposes.
return str(self) return str(self)
class MergedNodes(frozenset): class MergedNodes(frozenset):
def __init__(self, *args, **kwargs):
raise DeprecationWarning
pass pass

View File

@@ -8,6 +8,7 @@ from jedi.parser import tree
from jedi.evaluate import iterable from jedi.evaluate import iterable
from jedi.evaluate import analysis from jedi.evaluate import analysis
from jedi.evaluate import precedence from jedi.evaluate import precedence
from jedi.evaluate.context import Context
def try_iter_content(types, depth=0): def try_iter_content(types, depth=0):
@@ -27,7 +28,66 @@ def try_iter_content(types, depth=0):
try_iter_content(iter_types, depth + 1) try_iter_content(iter_types, depth + 1)
class Arguments(tree.Base): class AbstractArguments(tree.Base):
def get_parent_until(self, *args, **kwargs):
raise DeprecationWarning
if self.trailer is None:
try:
element = self.argument_node[0]
if isinstance(element, iterable.AlreadyEvaluated):
element = list(self._evaluator.eval_element(self._context, element))[0]
except IndexError:
return None
else:
return element.get_parent_until(*args, **kwargs)
else:
return self.trailer.get_parent_until(*args, **kwargs)
def eval_argument_clinic(self, arguments):
"""Uses a list with argument clinic information (see PEP 436)."""
raise DeprecationWarning('not sure if we really deprecate it')
iterator = self.unpack()
for i, (name, optional, allow_kwargs) in enumerate(arguments):
key, va_values = next(iterator, (None, []))
if key is not None:
raise NotImplementedError
if not va_values and not optional:
debug.warning('TypeError: %s expected at least %s arguments, got %s',
name, len(arguments), i)
raise ValueError
values = set(chain.from_iterable(self._evaluator.eval_element(self._context, el)
for el in va_values))
if not values and not optional:
# For the stdlib we always want values. If we don't get them,
# that's ok, maybe something is too hard to resolve, however,
# we will not proceed with the evaluation of that function.
debug.warning('argument_clinic "%s" not resolvable.', name)
raise ValueError
yield values
def scope(self):
raise DeprecationWarning
# Returns the scope in which the arguments are used.
return (self.trailer or self.argument_node).get_parent_until(tree.IsScope)
def eval_args(self):
# TODO this method doesn't work with named args and a lot of other
# things. Use unpack.
raise DeprecationWarning
return [self._evaluator.eval_element(self._context, el) for stars, el in self._split()]
def eval_all(self, func=None):
"""
Evaluates all arguments as a support for static analysis
(normally Jedi).
"""
for key, element_values in self.unpack():
for element in element_values:
types = self._evaluator.eval_element(self._context, element)
try_iter_content(types)
class TreeArguments(AbstractArguments):
def __init__(self, evaluator, context, argument_node, trailer=None): def __init__(self, evaluator, context, argument_node, trailer=None):
""" """
The argument_node is either a parser node or a list of evaluated The argument_node is either a parser node or a list of evaluated
@@ -66,32 +126,11 @@ class Arguments(tree.Base):
else: else:
yield 0, child yield 0, child
def get_parent_until(self, *args, **kwargs):
if self.trailer is None:
try:
element = self.argument_node[0]
from jedi.evaluate.iterable import AlreadyEvaluated
if isinstance(element, AlreadyEvaluated):
element = list(self._evaluator.eval_element(self._context, element))[0]
except IndexError:
return None
else:
return element.get_parent_until(*args, **kwargs)
else:
return self.trailer.get_parent_until(*args, **kwargs)
def as_tuple(self):
for stars, argument in self._split():
if tree.is_node(argument, 'argument'):
argument, default = argument.children[::2]
else:
default = None
yield argument, default, stars
def unpack(self, func=None): def unpack(self, func=None):
named_args = [] named_args = []
for stars, el in self._split(): for stars, el in self._split():
if stars == 1: if stars == 1:
raise NotImplementedError
arrays = self._evaluator.eval_element(self._context, el) arrays = self._evaluator.eval_element(self._context, el)
iterators = [_iterate_star_args(self._evaluator, a, el, func) iterators = [_iterate_star_args(self._evaluator, a, el, func)
for a in arrays] for a in arrays]
@@ -99,125 +138,101 @@ class Arguments(tree.Base):
for values in list(zip_longest(*iterators)): for values in list(zip_longest(*iterators)):
yield None, [v for v in values if v is not None] yield None, [v for v in values if v is not None]
elif stars == 2: elif stars == 2:
raise NotImplementedError
arrays = self._evaluator.eval_element(self._context, el) arrays = self._evaluator.eval_element(self._context, el)
dicts = [_star_star_dict(self._evaluator, a, el, func) dicts = [_star_star_dict(self._evaluator, a, el, func)
for a in arrays] for a in arrays]
for dct in dicts: for dct in dicts:
for key, values in dct.items(): for key, values in dct.items():
yield key, values yield key, LazyContext(*values)
else: else:
if tree.is_node(el, 'argument'): if tree.is_node(el, 'argument'):
c = el.children c = el.children
if len(c) == 3: # Keyword argument. if len(c) == 3: # Keyword argument.
named_args.append((c[0].value, (c[2],))) named_args.append((c[0].value, LazyContext(self._context, c[2]),))
else: # Generator comprehension. else: # Generator comprehension.
# Include the brackets with the parent. # Include the brackets with the parent.
comp = iterable.GeneratorComprehension( comp = iterable.GeneratorComprehension(
self._evaluator, self.argument_node.parent) self._evaluator, self.argument_node.parent)
yield None, (iterable.AlreadyEvaluated([comp]),) yield None, KnownContext(comp)
elif isinstance(el, (list, tuple)):
yield None, el
else: else:
yield None, (el,) yield None, LazyContext(self._context, el)
# Reordering var_args is necessary, because star args sometimes appear # Reordering var_args is necessary, because star args sometimes appear
# after named argument, but in the actual order it's prepended. # after named argument, but in the actual order it's prepended.
for key_arg in named_args: for named_arg in named_args:
yield key_arg yield named_arg
def _reorder_var_args(var_args): def as_tuple(self):
named_index = None raise DeprecationWarning
new_args = [] for stars, argument in self._split():
for i, stmt in enumerate(var_args): if tree.is_node(argument, 'argument'):
if isinstance(stmt, tree.ExprStmt): argument, default = argument.children[::2]
if named_index is None and stmt.assignment_details: else:
named_index = i default = None
yield argument, default, stars
if named_index is not None:
expression_list = stmt.expression_list()
if expression_list and expression_list[0] == '*':
new_args.insert(named_index, stmt)
named_index += 1
continue
new_args.append(stmt)
return new_args
def eval_argument_clinic(self, arguments):
"""Uses a list with argument clinic information (see PEP 436)."""
iterator = self.unpack()
for i, (name, optional, allow_kwargs) in enumerate(arguments):
key, va_values = next(iterator, (None, []))
if key is not None:
raise NotImplementedError
if not va_values and not optional:
debug.warning('TypeError: %s expected at least %s arguments, got %s',
name, len(arguments), i)
raise ValueError
values = set(chain.from_iterable(self._evaluator.eval_element(self._context, el)
for el in va_values))
if not values and not optional:
# For the stdlib we always want values. If we don't get them,
# that's ok, maybe something is too hard to resolve, however,
# we will not proceed with the evaluation of that function.
debug.warning('argument_clinic "%s" not resolvable.', name)
raise ValueError
yield values
def scope(self):
# Returns the scope in which the arguments are used.
return (self.trailer or self.argument_node).get_parent_until(tree.IsScope)
def eval_args(self):
# TODO this method doesn't work with named args and a lot of other
# things. Use unpack.
return [self._evaluator.eval_element(self._context, el) for stars, el in self._split()]
def __repr__(self): def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self.argument_node) return '<%s: %s>' % (type(self).__name__, self.argument_node)
def get_calling_var_args(self): def get_calling_var_args(self):
if tree.is_node(self.argument_node, 'arglist', 'argument') \ return _get_calling_var_args(self._evaluator, self)
or self.argument_node == () and self.trailer is not None:
return _get_calling_var_args(self._evaluator, self)
else:
return None
def eval_all(self, func=None):
"""
Evaluates all arguments as a support for static analysis
(normally Jedi).
"""
for key, element_values in self.unpack():
for element in element_values:
types = self._evaluator.eval_element(self._context, element)
try_iter_content(types)
class ExecutedParam(tree.Param): class KnownContext(object):
def __init__(self, value):
self._value = value
def infer(self):
return set([self._value])
class UnknownContext(object):
def infer(self):
return set()
class LazyContext(object):
def __init__(self, context, node):
self._context = context
self._node = node
def infer(self):
return self._context.eval_node(self._node)
class ValueArguments(AbstractArguments):
def __init__(self, value_list):
self._value_list = value_list
def unpack(self, func=None):
for value in self._value_list:
yield None, KnownContext(value)
def get_calling_var_args(self):
return None
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self._value_list)
class ExecutedParam(object):
"""Fake a param and give it values.""" """Fake a param and give it values."""
def __init__(self, original_param, var_args, values): def __init__(self, original_param, var_args, lazy_context):
assert not isinstance(lazy_context, (tuple, list))
self._original_param = original_param self._original_param = original_param
self.var_args = var_args self.var_args = var_args
self._values = values self._lazy_context = lazy_context
self.string_name = self._original_param.name.value self.string_name = self._original_param.name.value
def infer(self, evaluator): def infer(self, evaluator):
types = set() return self._lazy_context.infer()
for v in self._values:
# TODO this context selection seems wrong. Fix it once we change
# the way executed params work.
types |= evaluator.eval_element(self.var_args._context, v)
return types
@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._original_param.position_nr
def __getattr__(self, name):
return getattr(self._original_param, name)
def _get_calling_var_args(evaluator, var_args): def _get_calling_var_args(evaluator, var_args):
old_var_args = None old_var_args = None
@@ -244,7 +259,7 @@ def _get_calling_var_args(evaluator, var_args):
return var_args.argument_node or var_args.trailer return var_args.argument_node or var_args.trailer
def get_params(evaluator, func, var_args): def get_params(evaluator, parent_context, func, var_args):
result_params = [] result_params = []
param_dict = {} param_dict = {}
for param in func.params: for param in func.params:
@@ -252,8 +267,9 @@ def get_params(evaluator, func, var_args):
unpacked_va = list(var_args.unpack(func)) unpacked_va = list(var_args.unpack(func))
from jedi.evaluate.representation import InstanceElement from jedi.evaluate.representation import InstanceElement
if isinstance(func, InstanceElement): if isinstance(func, InstanceElement):
raise DeprecationWarning
# Include self at this place. # Include self at this place.
unpacked_va.insert(0, (None, [iterable.AlreadyEvaluated([func.instance])])) unpacked_va.insert(0, (None, [func.instance]))
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: [])
@@ -265,17 +281,17 @@ def get_params(evaluator, func, var_args):
# 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
# not allowed in Python, Jedi will maybe not show any completions. # not allowed in Python, Jedi will maybe not show any completions.
default = [] if param.default is None else [param.default] default = None if param.default is None else LazyContext(parent_context, param.default)
key, va_values = next(var_arg_iterator, (None, default)) key, argument = next(var_arg_iterator, (None, default))
while key is not None: while key is not None:
keys_only = True keys_only = True
k = unicode(key) k = unicode(key)
try: try:
key_param = param_dict[unicode(key)] key_param = param_dict[unicode(key)]
except KeyError: except KeyError:
non_matching_keys[key] = va_values non_matching_keys[key] = argument
else: else:
result_params.append(ExecutedParam(key_param, var_args, va_values)) result_params.append(ExecutedParam(key_param, var_args, argument))
if k in keys_used: if k in keys_used:
had_multiple_value_error = True had_multiple_value_error = True
@@ -291,43 +307,43 @@ def get_params(evaluator, func, var_args):
except IndexError: except IndexError:
# TODO this is wrong stupid and whatever. # TODO this is wrong stupid and whatever.
pass pass
key, va_values = next(var_arg_iterator, (None, ())) key, argument = next(var_arg_iterator, (None, None))
values = []
if param.stars == 1: if param.stars == 1:
# *args param # *args param
lst_values = [iterable.MergedNodes(va_values)] if va_values else [] values_list = []
for key, va_values in var_arg_iterator: if argument is not None:
# Iterate until a key argument is found. values_list.append([argument])
if key: for key, argument in var_arg_iterator:
var_arg_iterator.push_back((key, va_values)) # Iterate until a key argument is found.
break if key:
if va_values: var_arg_iterator.push_back((key, argument))
lst_values.append(iterable.MergedNodes(va_values)) break
seq = iterable.FakeSequence(evaluator, lst_values, 'tuple') values_list.append([argument])
values = [iterable.AlreadyEvaluated([seq])] seq = iterable.FakeSequence(evaluator, 'tuple', values_list)
result_arg = KnownContext(seq)
elif param.stars == 2: elif param.stars == 2:
# **kwargs param # **kwargs param
dct = iterable.FakeDict(evaluator, dict(non_matching_keys)) dct = iterable.FakeDict(evaluator, dict(non_matching_keys))
values = [iterable.AlreadyEvaluated([dct])] result_arg = KnownContext(dct)
non_matching_keys = {} non_matching_keys = {}
else: else:
# normal param # normal param
if va_values: if argument is not None:
values = va_values
else:
# No value: Return an empty container # No value: Return an empty container
values = [] result_arg = UnknownContext()
if not keys_only: if not keys_only:
calling_va = var_args.get_calling_var_args() calling_va = var_args.get_calling_var_args()
if calling_va is not None: if calling_va is not None:
m = _error_argument_count(func, len(unpacked_va)) m = _error_argument_count(func, len(unpacked_va))
analysis.add(evaluator, 'type-error-too-few-arguments', analysis.add(evaluator, 'type-error-too-few-arguments',
calling_va, message=m) calling_va, message=m)
else:
result_arg = argument
# Now add to result if it's not one of the previously covered cases. # Now add to result if it's not one of the previously covered cases.
if (not keys_only or param.stars == 2): if (not keys_only or param.stars == 2):
result_params.append(ExecutedParam(param, var_args, values)) result_params.append(ExecutedParam(param, var_args, result_arg))
keys_used[unicode(param.name)] = result_params[-1] keys_used[unicode(param.name)] = result_params[-1]
if keys_only: if keys_only:
@@ -336,8 +352,8 @@ def get_params(evaluator, func, var_args):
# there's nothing to find for certain names. # there's nothing to find for certain names.
for k in set(param_dict) - set(keys_used): for k in set(param_dict) - set(keys_used):
param = param_dict[k] param = param_dict[k]
values = [] if param.default is None else [param.default] result_arg = UnknownContext() if param.default is None else LazyContext(param.default)
result_params.append(ExecutedParam(param, var_args, values)) result_params.append(ExecutedParam(param, var_args, result_arg))
if not (non_matching_keys or had_multiple_value_error or if not (non_matching_keys or had_multiple_value_error or
param.stars or param.default): param.stars or param.default):
@@ -348,11 +364,10 @@ def get_params(evaluator, func, var_args):
analysis.add(evaluator, 'type-error-too-few-arguments', analysis.add(evaluator, 'type-error-too-few-arguments',
calling_va, message=m) calling_va, message=m)
for key, va_values in non_matching_keys.items(): for key, argument 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) % (func.name, key)
for value in va_values: analysis.add(evaluator, 'type-error-keyword-argument', argument.whatever, message=m)
analysis.add(evaluator, 'type-error-keyword-argument', value.parent, message=m)
remaining_params = list(var_arg_iterator) remaining_params = list(var_arg_iterator)
if remaining_params: if remaining_params:
@@ -383,7 +398,7 @@ def get_params(evaluator, func, var_args):
def _iterate_star_args(evaluator, array, input_node, func=None): def _iterate_star_args(evaluator, array, input_node, func=None):
from jedi.evaluate.representation import Instance from jedi.evaluate.representation import Instance
if isinstance(array, iterable.Array): if isinstance(array, iterable.AbstractSequence):
# TODO ._items is not the call we want here. Replace in the future. # TODO ._items is not the call we want here. Replace in the future.
for node in array._items(): for node in array._items():
yield node yield node

View File

@@ -767,7 +767,7 @@ class FunctionExecutionContext(Executed):
@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.funcdef, self.var_args) return param.get_params(self._evaluator, self.parent_context, self.funcdef, self.var_args)
def __repr__(self): def __repr__(self):
return "<%s of %s>" % (type(self).__name__, self.funcdef) return "<%s of %s>" % (type(self).__name__, self.funcdef)