diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index e4711988..9e0ef6a7 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -20,7 +20,6 @@ from parso import python_bytes_to_unicode, split_lines from jedi.parser_utils import get_executable_nodes, get_statement_of_position from jedi import debug from jedi import settings -from jedi import common from jedi import cache from jedi.api import classes from jedi.api import interpreter @@ -323,14 +322,13 @@ class Script(object): self._get_module(), call_signature_details.bracket_leaf ) - with common.scale_speed_settings(settings.scale_call_signatures): - definitions = helpers.cache_call_signatures( - self._evaluator, - context, - call_signature_details.bracket_leaf, - self._code_lines, - self._pos - ) + definitions = helpers.cache_call_signatures( + self._evaluator, + context, + call_signature_details.bracket_leaf, + self._code_lines, + self._pos + ) debug.speed('func_call followed') return [classes.CallSignature(self._evaluator, d.name, diff --git a/jedi/common.py b/jedi/common.py index 810ec127..007a1852 100644 --- a/jedi/common.py +++ b/jedi/common.py @@ -78,19 +78,6 @@ class PushBackIterator(object): return self.current -@contextlib.contextmanager -def scale_speed_settings(factor): - a = settings.max_executions - b = settings.max_until_execution_unique - settings.max_executions *= factor - settings.max_until_execution_unique *= factor - try: - yield - finally: - settings.max_executions = a - settings.max_until_execution_unique = b - - def indent_block(text, indention=' '): """This function indents a text block with a default of four spaces.""" temp = '' diff --git a/jedi/evaluate/recursion.py b/jedi/evaluate/recursion.py index 088fc93c..acb9ee55 100644 --- a/jedi/evaluate/recursion.py +++ b/jedi/evaluate/recursion.py @@ -6,13 +6,61 @@ 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? ``execution_recursion_decorator`` uses class variables to count the function calls. + +.. _settings-recursion: + +Settings +~~~~~~~~~~ + +Recursion settings are important if you don't want extremly +recursive python code to go absolutely crazy. First of there is a +global limit :data:`max_executions`. This limit is important, to set +a maximum amount of time, the completion may use. + +The default values are based on experiments while completing the |jedi| library +itself (inception!). But I don't think there's any other Python library that +uses recursion in a similarly extreme way. These settings make the completion +definitely worse in some cases. But a completion should also be fast. + +.. autodata:: max_until_execution_unique +.. autodata:: max_function_recursion_level +.. autodata:: max_executions_without_builtins +.. autodata:: max_executions """ + from contextlib import contextmanager from jedi import debug from jedi import settings +max_until_execution_unique = 50 +""" +This limit is probably the most important one, because if this limit is +exceeded, functions can only be one time executed. So new functions will be +executed, complex recursions with the same functions again and again, are +ignored. +""" + +max_function_recursion_level = 5 +""" +`max_function_recursion_level` is more about whether the recursions are +stopped in deepth or in width. The ratio beetween this and +`max_until_execution_unique` is important here. It stops a recursion (after +the number of function calls in the recursion), if it was already used +earlier. +""" + +max_executions_without_builtins = 200 +""" +.. todo:: Document this. +""" + +max_executions = 250 +""" +A maximum amount of time, the completion may use. +""" + class RecursionDetector(object): def __init__(self): self.pushed_nodes = [] @@ -64,39 +112,28 @@ class ExecutionRecursionDetector(object): self.execution_count = 0 self._evaluator = evaluator - 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): - result = set() - else: - result = self.func(execution) - self.pop_execution() - return result - def pop_execution(self): self.parent_execution_funcs.pop() self.recursion_level -= 1 def push_execution(self, execution): - in_par_execution_funcs = execution.tree_node in self.parent_execution_funcs - in_execution_funcs = execution.tree_node in self.execution_funcs self.recursion_level += 1 self.execution_count += 1 self.execution_funcs.add(execution.tree_node) self.parent_execution_funcs.append(execution.tree_node) if self.execution_count > settings.max_executions: + debug.warning('Too many executions %s' % execution) return True module = execution.get_root_context() if module == self._evaluator.BUILTINS: return False - if in_par_execution_funcs: + if execution.tree_node in self.parent_execution_funcs: if self.recursion_level > settings.max_function_recursion_level: return True - if in_execution_funcs and \ + if execution.tree_node in self.execution_funcs and \ len(self.execution_funcs) > settings.max_until_execution_unique: return True if self.execution_count > settings.max_executions_without_builtins: diff --git a/jedi/settings.py b/jedi/settings.py index ccb6889a..f1ae6dbb 100644 --- a/jedi/settings.py +++ b/jedi/settings.py @@ -43,28 +43,6 @@ Dynamic stuff .. autodata:: auto_import_modules -.. _settings-recursion: - -Recursions -~~~~~~~~~~ - -Recursion settings are important if you don't want extremly -recursive python code to go absolutely crazy. First of there is a -global limit :data:`max_executions`. This limit is important, to set -a maximum amount of time, the completion may use. - -The default values are based on experiments while completing the |jedi| library -itself (inception!). But I don't think there's any other Python library that -uses recursion in a similarly extreme way. These settings make the completion -definitely worse in some cases. But a completion should also be fast. - -.. autodata:: max_until_execution_unique -.. autodata:: max_function_recursion_level -.. autodata:: max_executions_without_builtins -.. autodata:: max_executions -.. autodata:: scale_call_signatures - - Caching ~~~~~~~ @@ -174,44 +152,6 @@ This improves autocompletion for libraries that use ``setattr`` or ``globals()`` modifications a lot. """ -# ---------------- -# recursions -# ---------------- - -max_until_execution_unique = 50 -""" -This limit is probably the most important one, because if this limit is -exceeded, functions can only be one time executed. So new functions will be -executed, complex recursions with the same functions again and again, are -ignored. -""" - -max_function_recursion_level = 5 -""" -`max_function_recursion_level` is more about whether the recursions are -stopped in deepth or in width. The ratio beetween this and -`max_until_execution_unique` is important here. It stops a recursion (after -the number of function calls in the recursion), if it was already used -earlier. -""" - -max_executions_without_builtins = 200 -""" -.. todo:: Document this. -""" - -max_executions = 250 -""" -A maximum amount of time, the completion may use. -""" - -scale_call_signatures = 0.1 -""" -Because call_signatures is normally used on every single key hit, it has -to be faster than a normal completion. This is the factor that is used to -scale `max_executions` and `max_until_execution_unique`: -""" - # ---------------- # caching validity (time) # ----------------