forked from VimPlug/jedi
Move the recursion limit settings to the recursion module.
This commit is contained in:
@@ -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.parser_utils import get_executable_nodes, get_statement_of_position
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
from jedi import common
|
|
||||||
from jedi import cache
|
from jedi import cache
|
||||||
from jedi.api import classes
|
from jedi.api import classes
|
||||||
from jedi.api import interpreter
|
from jedi.api import interpreter
|
||||||
@@ -323,7 +322,6 @@ class Script(object):
|
|||||||
self._get_module(),
|
self._get_module(),
|
||||||
call_signature_details.bracket_leaf
|
call_signature_details.bracket_leaf
|
||||||
)
|
)
|
||||||
with common.scale_speed_settings(settings.scale_call_signatures):
|
|
||||||
definitions = helpers.cache_call_signatures(
|
definitions = helpers.cache_call_signatures(
|
||||||
self._evaluator,
|
self._evaluator,
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -78,19 +78,6 @@ class PushBackIterator(object):
|
|||||||
return self.current
|
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=' '):
|
def indent_block(text, indention=' '):
|
||||||
"""This function indents a text block with a default of four spaces."""
|
"""This function indents a text block with a default of four spaces."""
|
||||||
temp = ''
|
temp = ''
|
||||||
|
|||||||
@@ -6,13 +6,61 @@ the right time. You can read more about them :ref:`here <settings-recursion>`.
|
|||||||
Next to :mod:`jedi.evaluate.cache` this module also makes |jedi| not
|
Next to :mod:`jedi.evaluate.cache` this module also makes |jedi| not
|
||||||
thread-safe. Why? ``execution_recursion_decorator`` uses class variables to
|
thread-safe. Why? ``execution_recursion_decorator`` uses class variables to
|
||||||
count the function calls.
|
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 contextlib import contextmanager
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import settings
|
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):
|
class RecursionDetector(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.pushed_nodes = []
|
self.pushed_nodes = []
|
||||||
@@ -64,39 +112,28 @@ class ExecutionRecursionDetector(object):
|
|||||||
self.execution_count = 0
|
self.execution_count = 0
|
||||||
self._evaluator = evaluator
|
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):
|
def pop_execution(self):
|
||||||
self.parent_execution_funcs.pop()
|
self.parent_execution_funcs.pop()
|
||||||
self.recursion_level -= 1
|
self.recursion_level -= 1
|
||||||
|
|
||||||
def push_execution(self, execution):
|
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.recursion_level += 1
|
||||||
self.execution_count += 1
|
self.execution_count += 1
|
||||||
self.execution_funcs.add(execution.tree_node)
|
self.execution_funcs.add(execution.tree_node)
|
||||||
self.parent_execution_funcs.append(execution.tree_node)
|
self.parent_execution_funcs.append(execution.tree_node)
|
||||||
|
|
||||||
if self.execution_count > settings.max_executions:
|
if self.execution_count > settings.max_executions:
|
||||||
|
debug.warning('Too many executions %s' % execution)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
module = execution.get_root_context()
|
module = execution.get_root_context()
|
||||||
if module == self._evaluator.BUILTINS:
|
if module == self._evaluator.BUILTINS:
|
||||||
return False
|
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:
|
if self.recursion_level > settings.max_function_recursion_level:
|
||||||
return True
|
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:
|
len(self.execution_funcs) > settings.max_until_execution_unique:
|
||||||
return True
|
return True
|
||||||
if self.execution_count > settings.max_executions_without_builtins:
|
if self.execution_count > settings.max_executions_without_builtins:
|
||||||
|
|||||||
@@ -43,28 +43,6 @@ Dynamic stuff
|
|||||||
.. autodata:: auto_import_modules
|
.. 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
|
Caching
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
@@ -174,44 +152,6 @@ This improves autocompletion for libraries that use ``setattr`` or
|
|||||||
``globals()`` modifications a lot.
|
``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)
|
# caching validity (time)
|
||||||
# ----------------
|
# ----------------
|
||||||
|
|||||||
Reference in New Issue
Block a user