forked from VimPlug/jedi
Taking a stab at simple *args and generators.
This commit is contained in:
@@ -25,12 +25,12 @@ class Context(object):
|
|||||||
from jedi.evaluate.param import ValueArguments
|
from jedi.evaluate.param import ValueArguments
|
||||||
return self.execute(ValueArguments(value_list))
|
return self.execute(ValueArguments(value_list))
|
||||||
|
|
||||||
|
|
||||||
class TreeContext(Context):
|
|
||||||
def eval_node(self, node):
|
def eval_node(self, node):
|
||||||
return self._evaluator.eval_element(self, node)
|
return self._evaluator.eval_element(self, node)
|
||||||
|
|
||||||
|
|
||||||
|
class TreeContext(Context):
|
||||||
|
pass
|
||||||
class FlowContext(TreeContext):
|
class FlowContext(TreeContext):
|
||||||
def get_parent_flow_context(self):
|
def get_parent_flow_context(self):
|
||||||
if 1:
|
if 1:
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class ParamName(ContextName):
|
|||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
return self._get_param().infer(self.parent_context._evaluator)
|
return self._get_param().infer()
|
||||||
|
|
||||||
def _get_param(self):
|
def _get_param(self):
|
||||||
params = self.parent_context.get_params()
|
params = self.parent_context.get_params()
|
||||||
|
|||||||
@@ -360,8 +360,8 @@ def _name_to_types(evaluator, context, name, scope):
|
|||||||
types = pep0484.find_type_from_comment_hint_with(evaluator, typ, name)
|
types = pep0484.find_type_from_comment_hint_with(evaluator, typ, name)
|
||||||
if types:
|
if types:
|
||||||
return types
|
return types
|
||||||
if typ.isinstance(tree.ForStmt, tree.CompFor):
|
if typ.type in ('for_stmt', 'comp_for'):
|
||||||
container_types = evaluator.eval_element(typ.children[3])
|
container_types = context.eval_node(typ.children[3])
|
||||||
for_types = iterable.py__iter__types(evaluator, container_types, typ.children[3])
|
for_types = iterable.py__iter__types(evaluator, container_types, typ.children[3])
|
||||||
types = check_tuple_assignments(evaluator, for_types, name)
|
types = check_tuple_assignments(evaluator, for_types, name)
|
||||||
elif isinstance(typ, tree.Param):
|
elif isinstance(typ, tree.Param):
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ def reachability_check(context, context_scope, node, origin_scope=None):
|
|||||||
# e.g. `if 0:` would cause all name lookup within the flow make
|
# e.g. `if 0:` would cause all name lookup within the flow make
|
||||||
# unaccessible. This is not a "problem" in Python, because the code is
|
# unaccessible. This is not a "problem" in Python, because the code is
|
||||||
# never called. In Jedi though, we still want to infer types.
|
# never called. In Jedi though, we still want to infer types.
|
||||||
while origin_scope is not None:
|
#while origin_scope is not None:
|
||||||
if flow_scope == origin_scope:
|
#if flow_scope == origin_scope:
|
||||||
return REACHABLE
|
#return REACHABLE
|
||||||
origin_scope = origin_scope.parent
|
#origin_scope = origin_scope.parent
|
||||||
|
|
||||||
return _break_check(context, context_scope, flow_scope, node)
|
return _break_check(context, context_scope, flow_scope, node)
|
||||||
|
|
||||||
|
|||||||
@@ -41,9 +41,7 @@ class AbstractSequence(Context):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
raise NotImplementedError
|
return compiled.CompiledContextName(self, self.type)
|
||||||
#return compiled.CompiledContextName(
|
|
||||||
return helpers.FakeName(self.type, parent=self)
|
|
||||||
|
|
||||||
|
|
||||||
class IterableWrapper(tree.Base):
|
class IterableWrapper(tree.Base):
|
||||||
@@ -137,19 +135,15 @@ class GeneratorMixin(object):
|
|||||||
return gen_obj.py__class__()
|
return gen_obj.py__class__()
|
||||||
|
|
||||||
|
|
||||||
class Generator(use_metaclass(CachedMetaClass, IterableWrapper, GeneratorMixin)):
|
class Generator(Context, GeneratorMixin):
|
||||||
"""Handling of `yield` functions."""
|
"""Handling of `yield` functions."""
|
||||||
|
|
||||||
def __init__(self, evaluator, func, var_args):
|
def __init__(self, evaluator, func_execution_context):
|
||||||
super(Generator, self).__init__()
|
super(Generator, self).__init__(evaluator)
|
||||||
self._evaluator = evaluator
|
self._func_execution_context = func_execution_context
|
||||||
self.func = func
|
|
||||||
self.var_args = var_args
|
|
||||||
|
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
from jedi.evaluate.representation import FunctionExecution
|
return self._func_execution_context.get_yield_values()
|
||||||
f = FunctionExecution(self._evaluator, self.func, self.var_args)
|
|
||||||
return f.get_yield_types()
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -389,13 +383,6 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
|
|||||||
else:
|
else:
|
||||||
return self.parent_context.eval_node(self._items()[index])
|
return self.parent_context.eval_node(self._items()[index])
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
raise NotImplementedError
|
|
||||||
if name not in ['start_pos', 'get_only_subelement', 'parent',
|
|
||||||
'get_parent_until', 'items']:
|
|
||||||
raise AttributeError('Strange access on %s: %s.' % (self, name))
|
|
||||||
return getattr(self.atom, name)
|
|
||||||
|
|
||||||
# @memoize_default()
|
# @memoize_default()
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
"""
|
"""
|
||||||
@@ -413,7 +400,7 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
|
|||||||
yield types
|
yield types
|
||||||
else:
|
else:
|
||||||
for value in self._items():
|
for value in self._items():
|
||||||
yield self._evaluator.eval_element(value)
|
yield self.parent_context.eval_node(value)
|
||||||
|
|
||||||
additions = check_array_additions(self._evaluator, self)
|
additions = check_array_additions(self._evaluator, self)
|
||||||
if additions:
|
if additions:
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ 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):
|
||||||
@@ -130,21 +129,19 @@ class TreeArguments(AbstractArguments):
|
|||||||
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]
|
||||||
iterators = list(iterators)
|
iterators = list(iterators)
|
||||||
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, MergedLazyContexts(values)
|
||||||
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, LazyContext(*values)
|
yield key, values
|
||||||
else:
|
else:
|
||||||
if tree.is_node(el, 'argument'):
|
if tree.is_node(el, 'argument'):
|
||||||
c = el.children
|
c = el.children
|
||||||
@@ -187,6 +184,14 @@ class KnownContext(object):
|
|||||||
return set([self._value])
|
return set([self._value])
|
||||||
|
|
||||||
|
|
||||||
|
class KnownContexts(object):
|
||||||
|
def __init__(self, values):
|
||||||
|
self._values = values
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
return self._values
|
||||||
|
|
||||||
|
|
||||||
class UnknownContext(object):
|
class UnknownContext(object):
|
||||||
def infer(self):
|
def infer(self):
|
||||||
return set()
|
return set()
|
||||||
@@ -201,6 +206,14 @@ class LazyContext(object):
|
|||||||
return self._context.eval_node(self._node)
|
return self._context.eval_node(self._node)
|
||||||
|
|
||||||
|
|
||||||
|
class MergedLazyContexts(object):
|
||||||
|
def __init__(self, lazy_contexts):
|
||||||
|
self._lazy_contexts = lazy_contexts
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
return common.unite(l.infer() for l in self._lazy_contexts)
|
||||||
|
|
||||||
|
|
||||||
class ValueArguments(AbstractArguments):
|
class ValueArguments(AbstractArguments):
|
||||||
def __init__(self, value_list):
|
def __init__(self, value_list):
|
||||||
self._value_list = value_list
|
self._value_list = value_list
|
||||||
@@ -225,7 +238,7 @@ class ExecutedParam(object):
|
|||||||
self._lazy_context = lazy_context
|
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):
|
||||||
return self._lazy_context.infer()
|
return self._lazy_context.infer()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -238,6 +251,7 @@ def _get_calling_var_args(evaluator, var_args):
|
|||||||
old_var_args = None
|
old_var_args = None
|
||||||
while var_args != old_var_args:
|
while var_args != old_var_args:
|
||||||
old_var_args = var_args
|
old_var_args = var_args
|
||||||
|
continue#TODO REMOVE
|
||||||
for name, default, stars in reversed(list(var_args.as_tuple())):
|
for name, default, stars in reversed(list(var_args.as_tuple())):
|
||||||
if not stars or not isinstance(name, tree.Name):
|
if not stars or not isinstance(name, tree.Name):
|
||||||
continue
|
continue
|
||||||
@@ -329,7 +343,7 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
non_matching_keys = {}
|
non_matching_keys = {}
|
||||||
else:
|
else:
|
||||||
# normal param
|
# normal param
|
||||||
if argument is not None:
|
if argument is None:
|
||||||
# No value: Return an empty container
|
# No value: Return an empty container
|
||||||
result_arg = UnknownContext()
|
result_arg = UnknownContext()
|
||||||
if not keys_only:
|
if not keys_only:
|
||||||
@@ -352,7 +366,8 @@ def get_params(evaluator, parent_context, 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]
|
||||||
result_arg = UnknownContext() if param.default is None else LazyContext(param.default)
|
result_arg = (UnknownContext() if param.default is None else
|
||||||
|
LazyContext(parent_context, param.default))
|
||||||
result_params.append(ExecutedParam(param, var_args, result_arg))
|
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
|
||||||
@@ -399,12 +414,13 @@ def get_params(evaluator, parent_context, 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.AbstractSequence):
|
if isinstance(array, iterable.AbstractSequence):
|
||||||
|
raise DeprecationWarning('_items? seriously?')
|
||||||
# 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
|
||||||
elif isinstance(array, iterable.Generator):
|
elif isinstance(array, iterable.Generator):
|
||||||
for types in array.py__iter__():
|
for types in array.py__iter__():
|
||||||
yield iterable.AlreadyEvaluated(types)
|
yield KnownContexts(types)
|
||||||
elif isinstance(array, Instance) and array.name.get_code() == 'tuple':
|
elif isinstance(array, Instance) and array.name.get_code() == 'tuple':
|
||||||
debug.warning('Ignored a tuple *args input %s' % array)
|
debug.warning('Ignored a tuple *args input %s' % array)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -603,15 +603,16 @@ class FunctionContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
|||||||
|
|
||||||
@Python3Method
|
@Python3Method
|
||||||
def py__call__(self, params):
|
def py__call__(self, params):
|
||||||
|
function_execution = FunctionExecutionContext(
|
||||||
|
self._evaluator,
|
||||||
|
self.parent_context,
|
||||||
|
self.base,
|
||||||
|
params
|
||||||
|
)
|
||||||
if self.base.is_generator():
|
if self.base.is_generator():
|
||||||
return set([iterable.Generator(self._evaluator, self, params)])
|
return set([iterable.Generator(self._evaluator, function_execution)])
|
||||||
else:
|
else:
|
||||||
return FunctionExecutionContext(
|
return function_execution.get_return_values()
|
||||||
self._evaluator,
|
|
||||||
self.parent_context,
|
|
||||||
self.base,
|
|
||||||
params
|
|
||||||
).get_return_types()
|
|
||||||
|
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
# This differentiation is only necessary for Python2. Python3 does not
|
# This differentiation is only necessary for Python2. Python3 does not
|
||||||
@@ -663,7 +664,7 @@ class FunctionExecutionContext(Executed):
|
|||||||
|
|
||||||
@memoize_default(default=set())
|
@memoize_default(default=set())
|
||||||
@recursion.execution_recursion_decorator
|
@recursion.execution_recursion_decorator
|
||||||
def get_return_types(self, check_yields=False):
|
def get_return_values(self, check_yields=False):
|
||||||
funcdef = self.funcdef
|
funcdef = self.funcdef
|
||||||
if funcdef.type in ('lambdef', 'lambdef_nocond'):
|
if funcdef.type in ('lambdef', 'lambdef_nocond'):
|
||||||
return self._evaluator.eval_element(self.children[-1])
|
return self._evaluator.eval_element(self.children[-1])
|
||||||
@@ -713,8 +714,8 @@ class FunctionExecutionContext(Executed):
|
|||||||
yield self.eval_node(node)
|
yield self.eval_node(node)
|
||||||
|
|
||||||
@recursion.execution_recursion_decorator
|
@recursion.execution_recursion_decorator
|
||||||
def get_yield_types(self):
|
def get_yield_values(self):
|
||||||
yields = self.yields
|
yields = self.funcdef.yields
|
||||||
stopAt = tree.ForStmt, tree.WhileStmt, tree.IfStmt
|
stopAt = tree.ForStmt, tree.WhileStmt, tree.IfStmt
|
||||||
for_parents = [(x, x.get_parent_until((stopAt))) for x in yields]
|
for_parents = [(x, x.get_parent_until((stopAt))) for x in yields]
|
||||||
|
|
||||||
@@ -736,7 +737,7 @@ class FunctionExecutionContext(Executed):
|
|||||||
elif for_stmt == self:
|
elif for_stmt == self:
|
||||||
yields_order.append((None, [yield_]))
|
yields_order.append((None, [yield_]))
|
||||||
else:
|
else:
|
||||||
yield self.get_return_types(check_yields=True)
|
yield self.get_return_values(check_yields=True)
|
||||||
return
|
return
|
||||||
last_for_stmt = for_stmt
|
last_for_stmt = for_stmt
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user