forked from VimPlug/jedi
Try to get star arguments working just a little bit.
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user