diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index af209ed9..e7bf22f4 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -73,7 +73,7 @@ from __future__ import with_statement import sys import itertools -from jedi._compatibility import next, hasattr, is_py3k, unicode, reraise, u +from jedi._compatibility import next, hasattr, unicode, reraise, u from jedi import common from jedi.parser import representation as pr from jedi import debug @@ -310,7 +310,7 @@ class Evaluator(object): # one, remember `in`). And follow it. if not loop.inputs: return [] - result = get_iterator_types(self.eval_statement(loop.inputs[0])) + result = iterable.get_iterator_types(self.eval_statement(loop.inputs[0])) if len(loop.set_vars) > 1: expression_list = loop.set_stmt.expression_list() # loops with loop.set_vars > 0 only have one command @@ -758,43 +758,6 @@ def check_getattr(inst, name_str): return result -def get_iterator_types(inputs): - """Returns the types of any iterator (arrays, yields, __iter__, etc).""" - iterators = [] - # Take the first statement (for has always only - # one, remember `in`). And follow it. - for it in inputs: - if isinstance(it, (iterable.Generator, iterable.Array, iterable.ArrayInstance)): - iterators.append(it) - else: - if not hasattr(it, 'execute_subscope_by_name'): - debug.warning('iterator/for loop input wrong', it) - continue - try: - iterators += it.execute_subscope_by_name('__iter__') - except KeyError: - debug.warning('iterators: No __iter__ method found.') - - result = [] - for gen in iterators: - if isinstance(gen, iterable.Array): - # Array is a little bit special, since this is an internal - # array, but there's also the list builtin, which is - # another thing. - result += gen.get_index_types() - elif isinstance(gen, er.Instance): - # __iter__ returned an instance. - name = '__next__' if is_py3k else 'next' - try: - result += gen.execute_subscope_by_name(name) - except KeyError: - debug.warning('Instance has no __next__ function', gen) - else: - # is a generator - result += gen.iter_content() - return result - - def assign_tuples(tup, results, seek_name): """ This is a normal assignment checker. In python functions and other things diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index b12624e5..5a90d8ae 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -3,7 +3,7 @@ import itertools from jedi import common from jedi import debug from jedi import settings -from jedi._compatibility import use_metaclass +from jedi._compatibility import use_metaclass, is_py3k from jedi.parser import representation as pr from jedi.evaluate import builtin from jedi.evaluate.cache import CachedMetaClass, memoize_default @@ -182,6 +182,44 @@ class ArrayMethod(object): return "<%s of %s>" % (type(self).__name__, self.name) +def get_iterator_types(inputs): + """Returns the types of any iterator (arrays, yields, __iter__, etc).""" + iterators = [] + # Take the first statement (for has always only + # one, remember `in`). And follow it. + for it in inputs: + if isinstance(it, (Generator, Array, ArrayInstance)): + iterators.append(it) + else: + if not hasattr(it, 'execute_subscope_by_name'): + debug.warning('iterator/for loop input wrong', it) + continue + try: + iterators += it.execute_subscope_by_name('__iter__') + except KeyError: + debug.warning('iterators: No __iter__ method found.') + + result = [] + from jedi.evaluate.representation import Instance + for gen in iterators: + if isinstance(gen, Array): + # Array is a little bit special, since this is an internal + # array, but there's also the list builtin, which is + # another thing. + result += gen.get_index_types() + elif isinstance(gen, Instance): + # __iter__ returned an instance. + name = '__next__' if is_py3k else 'next' + try: + result += gen.execute_subscope_by_name(name) + except KeyError: + debug.warning('Instance has no __next__ function', gen) + else: + # is a generator + result += gen.iter_content() + return result + + def check_array_additions(evaluator, array): """ Just a mapper function for the internal _check_array_additions """ if not pr.Array.is_type(array._array, pr.Array.LIST, pr.Array.SET): @@ -242,11 +280,10 @@ def _check_array_additions(evaluator, compare_array, module, is_list): elif add_name in ['extend', 'update']: for param in params: iterators = evaluator.eval_statement(param) - result += evaluate.get_iterator_types(iterators) + result += get_iterator_types(iterators) return result from jedi.evaluate import representation as er - from jedi import evaluate def get_execution_parent(element, *stop_classes): """ Used to get an Instance/FunctionExecution parent """ @@ -326,10 +363,10 @@ class ArrayInstance(pr.Base): lists/sets are too complicated too handle that. """ items = [] - from jedi import evaluate + from jedi.evaluate.representation import Instance for stmt in self.var_args: for typ in self._evaluator.eval_statement(stmt): - if isinstance(typ, evaluate.er.Instance) and len(typ.var_args): + if isinstance(typ, Instance) and len(typ.var_args): array = typ.var_args[0] if isinstance(array, ArrayInstance): # prevent recursions @@ -341,7 +378,7 @@ class ArrayInstance(pr.Base): 'ArrayInstance recursion', self.var_args) continue - items += evaluate.get_iterator_types([typ]) + items += get_iterator_types([typ]) # TODO check if exclusion of tuple is a problem here. if isinstance(self.var_args, tuple) or self.var_args.parent is None: