diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index 7491b589..c1f72283 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -62,7 +62,10 @@ class Generator(use_metaclass(CachedMetaClass, pr.Base)): def iter_content(self): """ returns the content of __iter__ """ - return self.func.py__call__(self._evaluator, self.var_args, True) + # Directly execute it, because with a normal call to py__call__ a + # Generator will be returned. + from jedi.evaluate.representation import FunctionExecution + return FunctionExecution(self._evaluator, self.func, self.var_args).get_return_types() def get_index_types(self, index_array): #debug.warning('Tried to get array access on a generator: %s', self) @@ -285,6 +288,7 @@ def get_iterator_types(inputs): except KeyError: debug.warning('Instance has no __next__ function in %s.', it) else: + # TODO this is not correct, __iter__ can return arbitrary input! # Is a generator. result += it.iter_content() return result diff --git a/jedi/evaluate/recursion.py b/jedi/evaluate/recursion.py index a07299bb..f4809db0 100644 --- a/jedi/evaluate/recursion.py +++ b/jedi/evaluate/recursion.py @@ -4,7 +4,7 @@ must stop recursions going mad. Some settings are here to make |jedi| stop at the right time. You can read more about them :ref:`here `. Next to :mod:`jedi.evaluate.cache` this module also makes |jedi| not -thread-safe. Why? ``ExecutionRecursionDecorator`` uses class variables to +thread-safe. Why? ``execution_recursion_decorator`` uses class variables to count the function calls. """ from jedi.parser import representation as pr @@ -100,12 +100,12 @@ class _RecursionNode(object): def execution_recursion_decorator(func): - def run(execution, evaluate_generator=False): + def run(execution): detector = execution._evaluator.execution_recursion_detector - if detector.push_execution(execution, evaluate_generator): + if detector.push_execution(execution): result = [] else: - result = func(execution, evaluate_generator) + result = func(execution) detector.pop_execution() return result @@ -123,13 +123,13 @@ class ExecutionRecursionDetector(object): self.execution_funcs = set() self.execution_count = 0 - def __call__(self, execution, evaluate_generator=False): + def __call__(self, execution): debug.dbg('Execution recursions: %s', execution, self.recursion_level, self.execution_count, len(self.execution_funcs)) - if self.check_recursion(execution, evaluate_generator): + if self.check_recursion(execution): result = [] else: - result = self.func(execution, evaluate_generator) + result = self.func(execution) self.pop_execution() return result @@ -137,7 +137,7 @@ class ExecutionRecursionDetector(object): cls.parent_execution_funcs.pop() cls.recursion_level -= 1 - def push_execution(cls, execution, evaluate_generator): + def push_execution(cls, execution): in_par_execution_funcs = execution.base in cls.parent_execution_funcs in_execution_funcs = execution.base in cls.execution_funcs cls.recursion_level += 1 @@ -151,7 +151,7 @@ class ExecutionRecursionDetector(object): if isinstance(execution.base, (iterable.Array, iterable.Generator)): return False module = execution.get_parent_until() - if evaluate_generator or module == compiled.builtin: + if module == compiled.builtin: return False if in_par_execution_funcs: diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 8e4473f2..4068f49a 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -250,12 +250,13 @@ class InstanceElement(use_metaclass(CachedMetaClass, pr.Base)): def isinstance(self, *cls): return isinstance(self.var, cls) - def py__call__(self, evaluator, params, evaluate_generator=False): + def py__call__(self, evaluator, params): # TODO this should be working nicer. if isinstance(self.var, (compiled.CompiledObject, Instance)): return self.var.py__call__(evaluator, params) - stmts = FunctionExecution(evaluator, self, params) \ - .get_return_types(evaluate_generator) + if self.is_generator: + return [iterable.Generator(evaluator, self, params)] + stmts = FunctionExecution(evaluator, self, params).get_return_types() return stmts def __repr__(self): @@ -421,10 +422,11 @@ class Function(use_metaclass(CachedMetaClass, pr.IsScope)): def get_magic_function_scope(self): return compiled.magic_function_class - def py__call__(self, evaluator, params, evaluate_generator=False): - stmts = FunctionExecution(evaluator, self, params) \ - .get_return_types(evaluate_generator) - return stmts + def py__call__(self, evaluator, params): + if self.is_generator: + return [iterable.Generator(evaluator, self, params)] + else: + return FunctionExecution(evaluator, self, params).get_return_types() def __getattr__(self, name): return getattr(self.base_func, name) @@ -448,7 +450,7 @@ class FunctionExecution(Executed): """ @memoize_default(default=()) @recursion.execution_recursion_decorator - def get_return_types(self, evaluate_generator=False): + def get_return_types(self): func = self.base # Feed the listeners, with the params. for listener in func.listeners: @@ -459,14 +461,11 @@ class FunctionExecution(Executed): # inserted params, not in the actual execution of the function. return [] - if func.is_generator and not evaluate_generator: - return [iterable.Generator(self._evaluator, func, self.var_args)] - else: - stmts = list(docstrings.find_return_types(self._evaluator, func)) - for r in self.returns: - if r is not None: - stmts += self._evaluator.eval_statement(r) - return imports.follow_imports(self._evaluator, stmts) + stmts = list(docstrings.find_return_types(self._evaluator, func)) + for r in self.returns: + if r is not None: + stmts += self._evaluator.eval_statement(r) + return imports.follow_imports(self._evaluator, stmts) @memoize_default(default=()) def _get_params(self):