diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index a1e60c5b..405f731c 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -410,9 +410,6 @@ class Evaluator(object): if self.is_analysis: arguments.eval_all() - if isinstance(obj, er.FunctionContext): - obj = obj.get_decorated_func() - debug.dbg('execute: %s %s', obj, arguments) try: # Some stdlib functions like super(), namedtuple(), etc. have been diff --git a/jedi/evaluate/context.py b/jedi/evaluate/context.py index 2d5b0b23..cb83ee5d 100644 --- a/jedi/evaluate/context.py +++ b/jedi/evaluate/context.py @@ -23,8 +23,8 @@ class Context(object): """ Execute a function with already executed arguments. """ - from jedi.evaluate.param import ValueArguments - return self.execute(ValueArguments(value_list)) + from jedi.evaluate.param import ValuesArguments + return self.execute(ValuesArguments(value_list)) def eval_node(self, node): return self._evaluator.eval_element(self, node) diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index ee494bb6..98951665 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -351,50 +351,81 @@ def _get_global_stmt_scopes(evaluator, global_stmt, name): @memoize_default(set(), evaluator_is_first_arg=True) def _name_to_types(evaluator, context, name, scope): types = [] - typ = name.get_definition() - if typ.isinstance(tree.ForStmt): - types = pep0484.find_type_from_comment_hint_for(evaluator, typ, name) + node = name.get_definition() + if node.isinstance(tree.ForStmt): + types = pep0484.find_type_from_comment_hint_for(evaluator, node, name) if types: return types - if typ.isinstance(tree.WithStmt): - types = pep0484.find_type_from_comment_hint_with(evaluator, typ, name) + if node.isinstance(tree.WithStmt): + types = pep0484.find_type_from_comment_hint_with(evaluator, node, name) if types: return types - if typ.type in ('for_stmt', 'comp_for'): - container_types = context.eval_node(typ.children[3]) - for_types = iterable.py__iter__types(evaluator, container_types, typ.children[3]) + if node.type in ('for_stmt', 'comp_for'): + container_types = context.eval_node(node.children[3]) + for_types = iterable.py__iter__types(evaluator, container_types, node.children[3]) types = check_tuple_assignments(evaluator, for_types, name) - elif isinstance(typ, tree.Param): - types = _eval_param(evaluator, context, typ, scope) - elif typ.isinstance(tree.ExprStmt): - types = _remove_statements(evaluator, context, typ, name) - elif typ.isinstance(tree.WithStmt): - types = evaluator.eval_element(typ.node_from_name(name)) - elif isinstance(typ, tree.Import): + elif isinstance(node, tree.Param): + return set() # TODO remove + types = _eval_param(evaluator, context, node, scope) + elif node.isinstance(tree.ExprStmt): + types = _remove_statements(evaluator, context, node, name) + elif node.isinstance(tree.WithStmt): + types = evaluator.eval_element(node.node_from_name(name)) + elif isinstance(node, tree.Import): types = imports.ImportWrapper(evaluator, name).follow() - elif typ.isinstance(tree.Function, tree.Class): - types = [evaluator.wrap(typ, parent_context=context)] - elif typ.type == 'global_stmt': - for s in _get_global_stmt_scopes(evaluator, typ, name): + elif node.type in ('funcdef', 'classdef'): + types = _apply_decorators(evaluator, context, node) + elif node.type == 'global_stmt': + for s in _get_global_stmt_scopes(evaluator, node, name): finder = NameFinder(evaluator, s, str(name)) names_dicts = finder.get_filters(search_global=True) # For global_stmt lookups, we only need the first possible scope, # which means the function itself. names_dicts = [next(names_dicts)] types += finder.find(names_dicts, attribute_lookup=False) - elif isinstance(typ, tree.TryStmt): + elif isinstance(node, tree.TryStmt): # TODO an exception can also be a tuple. Check for those. # TODO check for types that are not classes and add it to # the static analysis report. exceptions = evaluator.eval_element(name.get_previous_sibling().get_previous_sibling()) types = set(chain.from_iterable(evaluator.execute(t) for t in exceptions)) else: - if typ.isinstance(er.Function): - typ = typ.get_decorated_func() - types = set([typ]) + raise DeprecationWarning + types = set([node]) return types +def _apply_decorators(evaluator, context, node): + """ + Returns the function, that should to be executed in the end. + This is also the places where the decorators are processed. + """ + decoratee_context = evaluator.wrap(node, parent_context=context) + initial = values = set([decoratee_context]) + for dec in reversed(node.get_decorators()): + debug.dbg('decorator: %s %s', dec, values) + dec_values = context.eval_node(dec.children[1]) + trailer = dec.children[2:-1] + if trailer: + # Create a trailer and evaluate it. + trailer = tree.Node('trailer', trailer) + trailer.parent = dec + dec_values = context.eval_trailer(dec_values, trailer) + + if not len(dec_values): + debug.warning('decorator not found: %s on %s', dec, node) + return initial + + values = unite(dec_value.execute(param.ValuesArguments([values])) + for dec_value in dec_values) + if not len(values): + debug.warning('not possible to resolve wrappers found %s', node) + return initial + + debug.dbg('decorator end %s', values) + return values + + def _remove_statements(evaluator, context, stmt, name): """ This is the part where statements are being stripped. diff --git a/jedi/evaluate/instance.py b/jedi/evaluate/instance.py index 3f6cdd0f..56d515e1 100644 --- a/jedi/evaluate/instance.py +++ b/jedi/evaluate/instance.py @@ -188,8 +188,7 @@ class InstanceClassFilter(ParserTreeFilter): def _filter(self, names): names = super(InstanceClassFilter, self)._filter(names) - return [get_instance_el(self._evaluator, self._context, name, True) - for name in names if self._access_possible(name)] + return [name for name in names if self._access_possible(name)] def _check_flows(self, names): return names @@ -207,7 +206,7 @@ class SelfNameFilter(InstanceClassFilter): def _filter_self_names(self, names): for name in names: trailer = name.parent - if tree.is_node(trailer, 'trailer') \ + if trailer.type == 'trailer' \ and len(trailer.children) == 2 \ and trailer.children[0] == '.': if name.is_definition() and self._access_possible(name): @@ -216,4 +215,4 @@ class SelfNameFilter(InstanceClassFilter): if init_execution is not None and \ init_execution.start_pos < name.start_pos < init_execution.end_pos: name = init_execution.name_for_position(name.start_pos) - yield get_instance_el(self._evaluator, self._context, name) + yield name diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index b0ede166..39b7998d 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -386,6 +386,7 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin): function returns the value for a certain index. """ if self.type == 'dict': + raise NotImplementedError # Get keys. types = set() for k, _ in self._items(): @@ -442,9 +443,11 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin): class _FakeArray(ArrayLiteralContext): def __init__(self, evaluator, container, type): - self.type = type + # TODO is this class really needed? + self._array_type = type self._evaluator = evaluator self.atom = container + self.parent_context = evaluator.BUILTINS class ImplicitTuple(_FakeArray): @@ -458,28 +461,25 @@ class ImplicitTuple(_FakeArray): class FakeSequence(_FakeArray): - def __init__(self, evaluator, type, context_sets): + def __init__(self, evaluator, array_type, lazy_context_list): """ type should be one of "tuple", "list" """ - super(FakeSequence, self).__init__(evaluator, context_sets, type) - 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 + super(FakeSequence, self).__init__(evaluator, None, array_type) + self._lazy_context_list = lazy_context_list def _items(self): - return self._context_sets + raise DeprecationWarning + return self._context_list def py__getitem__(self, index): - return set(self._resolve(self._context_sets[index])) + return self._lazy_context_list[index].infer() + + def py__iter__(self): + return self._lazy_context_list + + def __repr__(self): + return "<%s of %s>" % (type(self).__name__, self._lazy_context_list) def create_evaluated_sequence_set(evaluator, *types_order, **kwargs): @@ -520,9 +520,10 @@ class FakeDict(_FakeArray): yield set(compiled.create(self._evaluator, key) for key in self._dct) def py__getitem__(self, index): - return unite(self._evaluator.eval_element(v) for v in self._dct[index]) + return self._dct[index].infer() def _items(self): + raise DeprecationWarning for key, values in self._dct.items(): # TODO this is not proper. The values could be multiple values?! yield key, values[0] diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index e24f1ae2..17ec2b4d 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -130,11 +130,13 @@ class TreeArguments(AbstractArguments): named_args = [] for stars, el in self._split(): if stars == 1: - arrays = self._evaluator.eval_element(self._context, el) + arrays = self._context.eval_node(el) iterators = [_iterate_star_args(self._evaluator, a, el, func) for a in arrays] iterators = list(iterators) for values in list(zip_longest(*iterators)): + # TODO zip_longest yields None, that means this would raise + # an exception? yield None, context.get_merged_lazy_context(values) elif stars == 2: arrays = self._evaluator.eval_element(self._context, el) @@ -142,6 +144,7 @@ class TreeArguments(AbstractArguments): for a in arrays] for dct in dicts: for key, values in dct.items(): + raise NotImplementedError yield key, values else: if tree.is_node(el, 'argument'): @@ -177,19 +180,19 @@ class TreeArguments(AbstractArguments): return _get_calling_var_args(self._evaluator, self) -class ValueArguments(AbstractArguments): - def __init__(self, value_list): - self._value_list = value_list +class ValuesArguments(AbstractArguments): + def __init__(self, values_list): + self._values_list = values_list def unpack(self, func=None): - for value in self._value_list: - yield None, context.LazyKnownContext(value) + for values in self._values_list: + yield None, context.LazyKnownContexts(values) def get_calling_var_args(self): return None def __repr__(self): - return '<%s: %s>' % (type(self).__name__, self._value_list) + return '<%s: %s>' % (type(self).__name__, self._values_list) class ExecutedParam(object): @@ -242,11 +245,10 @@ def get_params(evaluator, parent_context, func, var_args): for param in func.params: param_dict[str(param.name)] = param unpacked_va = list(var_args.unpack(func)) - from jedi.evaluate.representation import InstanceElement - if isinstance(func, InstanceElement): - raise DeprecationWarning - # Include self at this place. - unpacked_va.insert(0, (None, [func.instance])) + from jedi.evaluate.instance import TreeInstance + if isinstance(parent_context, TreeInstance): + # Include the self parameter here. + unpacked_va.insert(0, (None, context.LazyKnownContext(parent_context))) var_arg_iterator = common.PushBackIterator(iter(unpacked_va)) non_matching_keys = defaultdict(lambda: []) @@ -291,16 +293,16 @@ def get_params(evaluator, parent_context, func, var_args): if param.stars == 1: # *args param - values_list = [] + lazy_context_list = [] if argument is not None: - values_list.append([argument]) + lazy_context_list.append(argument) for key, argument in var_arg_iterator: # Iterate until a key argument is found. if key: var_arg_iterator.push_back((key, argument)) break - values_list.append([argument]) - seq = iterable.FakeSequence(evaluator, 'tuple', values_list) + lazy_context_list.append(argument) + seq = iterable.FakeSequence(evaluator, 'tuple', lazy_context_list) result_arg = context.LazyKnownContext(seq) elif param.stars == 2: # **kwargs param diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index ff48b665..933378a5 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -522,68 +522,10 @@ class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrappe """ Needed because of decorators. Decorators are evaluated here. """ - def __init__(self, evaluator, parent_context, func, is_decorated=False): + def __init__(self, evaluator, parent_context, func): """ This should not be called directly """ super(FunctionContext, self).__init__(evaluator, parent_context) self.base = self.base_func = func - self.is_decorated = is_decorated - # A property that is set by the decorator resolution. - self.decorates = None - - @memoize_default() - def get_decorated_func(self): - """ - Returns the function, that should to be executed in the end. - This is also the places where the decorators are processed. - """ - f = self.base_func - decorators = self.base_func.get_decorators() - - if not decorators or self.is_decorated: - return self - - # Only enter it, if has not already been processed. - if not self.is_decorated: - for dec in reversed(decorators): - debug.dbg('decorator: %s %s', dec, f) - dec_results = self._evaluator.eval_element(dec.children[1]) - trailer = dec.children[2:-1] - if trailer: - # Create a trailer and evaluate it. - trailer = tree.Node('trailer', trailer) - trailer.parent = dec - dec_results = self._evaluator.eval_trailer(dec_results, trailer) - - if not len(dec_results): - debug.warning('decorator not found: %s on %s', dec, self.base_func) - return self - decorator = dec_results.pop() - if dec_results: - debug.warning('multiple decorators found %s %s', - self.base_func, dec_results) - - # Create param array. - if isinstance(f, FunctionContext): - old_func = f # TODO this is just hacky. change. - elif f.type == 'funcdef': - old_func = FunctionContext(self._evaluator, f, is_decorated=True) - else: - old_func = f - - wrappers = self._evaluator.execute_evaluated(decorator, old_func) - if not len(wrappers): - debug.warning('no wrappers found %s', self.base_func) - return self - if len(wrappers) > 1: - # TODO resolve issue with multiple wrappers -> multiple types - debug.warning('multiple wrappers found %s %s', - self.base_func, wrappers) - f = list(wrappers)[0] - if isinstance(f, (Instance, FunctionContext)): - f.decorates = self - - debug.dbg('decorator end %s', f) - return f def names_dicts(self, search_global): if search_global: @@ -624,10 +566,7 @@ class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrappe return compiled.get_special_object(self._evaluator, name) def __repr__(self): - dec = '' - if self.decorates is not None: - dec = " decorates " + repr(self.decorates) - return "" % (type(self).__name__, self.base_func, dec) + return "" % (type(self).__name__, self.base_func) class LambdaWrapper(FunctionContext):