diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 95162da2..d927cb23 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -24,7 +24,7 @@ def _clear_caches(): """ cache.clear_caches() dynamic.search_param_cache.clear() - #recursion.ExecutionRecursionDecorator.reset() + recursion.ExecutionRecursionDecorator.reset() evaluate.follow_statement.reset() diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 53f90904..5cfd5a38 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -117,7 +117,8 @@ def get_defined_names_for_position(scope, position=None, start_scope=None): class Evaluator(object): def __init__(self): - self.memoize_cache = {} + self.memoize_cache = {} # for memoize decorators + self.recursion_detector = recursion.RecursionDetector() def get_names_of_scope(self, scope, position=None, star_search=True, include_builtin=True): @@ -475,7 +476,7 @@ class Evaluator(object): return descriptor_check(remove_statements(filter_name(scope_generator))) @memoize_default(default=(), cache_is_in_self=True) - @recursion.RecursionDecorator + @recursion.recursion_decorator def follow_statement(self, stmt, seek_name=None): """ The starting point of the completion. A statement always owns a call list, diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 2d423848..c6a5d913 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -187,7 +187,7 @@ class ImportPath(pr.Base): """ Returns the imported modules. """ - if self._evaluator.follow_statement.push_stmt(self.import_stmt): + if self._evaluator.recursion_detector.push_stmt(self.import_stmt): # check recursion return [] @@ -229,7 +229,7 @@ class ImportPath(pr.Base): scopes = [ImportPath.GlobalNamespace] debug.dbg('after import', scopes) - self._evaluator.follow_statement.pop_stmt() + self._evaluator.recursion_detector.pop_stmt() return scopes def _is_relative_import(self): diff --git a/jedi/evaluate/recursion.py b/jedi/evaluate/recursion.py index e80f2f9d..566fd23c 100644 --- a/jedi/evaluate/recursion.py +++ b/jedi/evaluate/recursion.py @@ -14,23 +14,27 @@ from jedi.evaluate import builtin from jedi.evaluate import interfaces -class RecursionDecorator(object): +def recursion_decorator(func): + def run(evaluator, stmt, *args, **kwargs): + rec_detect = evaluator.recursion_detector + # print stmt, len(self.node_statements()) + if rec_detect.push_stmt(stmt): + return [] + else: + result = func(evaluator, stmt, *args, **kwargs) + rec_detect.pop_stmt() + return result + return run + + +class RecursionDetector(object): """ A decorator to detect recursions in statements. In a recursion a statement at the same place, in the same module may not be executed two times. """ - def __init__(self, func): - self.func = func - self.reset() - - def __call__(self, evaluator, stmt, *args, **kwargs): - # print stmt, len(self.node_statements()) - if self.push_stmt(stmt): - return [] - else: - result = self.func(evaluator, stmt, *args, **kwargs) - self.pop_stmt() - return result + def __init__(self): + self.top = None + self.current = None def push_stmt(self, stmt): self.current = _RecursionNode(stmt, self.current) @@ -57,10 +61,6 @@ class RecursionDecorator(object): if not test: return False - def reset(self): - self.top = None - self.current = None - def node_statements(self): result = [] n = self.current