forked from VimPlug/jedi
Fix recursion issues about dynamic param lookups and defaults work again
This commit is contained in:
@@ -23,40 +23,38 @@ from jedi.parser_utils import get_parent_scope
|
|||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
from jedi.inference import imports
|
from jedi.inference import imports
|
||||||
from jedi.inference.arguments import TreeArguments
|
from jedi.inference.arguments import TreeArguments
|
||||||
from jedi.inference.param import create_default_params, get_executed_param_names
|
from jedi.inference.param import get_executed_param_names
|
||||||
from jedi.inference.helpers import is_stdlib_path
|
from jedi.inference.helpers import is_stdlib_path
|
||||||
from jedi.inference.utils import to_list
|
from jedi.inference.utils import to_list
|
||||||
from jedi.inference.value import instance
|
from jedi.inference.value import instance
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference import recursion
|
from jedi.inference import recursion
|
||||||
from jedi.inference.names import ParamNameWrapper
|
|
||||||
|
|
||||||
|
|
||||||
MAX_PARAM_SEARCHES = 20
|
MAX_PARAM_SEARCHES = 20
|
||||||
|
|
||||||
|
|
||||||
class DynamicExecutedParamName(ParamNameWrapper):
|
def _avoid_recursions(func):
|
||||||
"""
|
def wrapper(function_value, param_index):
|
||||||
Simulates being a parameter while actually just being multiple params.
|
inf = function_value.inference_state
|
||||||
"""
|
with recursion.execution_allowed(inf, function_value.tree_node) as allowed:
|
||||||
|
|
||||||
def __init__(self, executed_param_names):
|
|
||||||
super(DynamicExecutedParamName, self).__init__(executed_param_names[0])
|
|
||||||
self._executed_param_names = executed_param_names
|
|
||||||
|
|
||||||
def infer(self):
|
|
||||||
inf = self.parent_context.inference_state
|
|
||||||
with recursion.execution_allowed(inf, self.tree_name) as allowed:
|
|
||||||
# We need to catch recursions that may occur, because an
|
# We need to catch recursions that may occur, because an
|
||||||
# anonymous functions can create an anonymous parameter that is
|
# anonymous functions can create an anonymous parameter that is
|
||||||
# more or less self referencing.
|
# more or less self referencing.
|
||||||
if allowed:
|
if allowed:
|
||||||
return ValueSet.from_sets(p.infer() for p in self._executed_param_names)
|
inf.dynamic_params_depth += 1
|
||||||
|
try:
|
||||||
|
return func(function_value, param_index)
|
||||||
|
finally:
|
||||||
|
inf.dynamic_params_depth -= 1
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
|
return
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@debug.increase_indent
|
@debug.increase_indent
|
||||||
def search_param_names(function_value):
|
@_avoid_recursions
|
||||||
|
def dynamic_param_lookup(function_value, param_index):
|
||||||
"""
|
"""
|
||||||
A dynamic search for param values. If you try to complete a type:
|
A dynamic search for param values. If you try to complete a type:
|
||||||
|
|
||||||
@@ -69,51 +67,43 @@ def search_param_names(function_value):
|
|||||||
have to look for all calls to ``func`` to find out what ``foo`` possibly
|
have to look for all calls to ``func`` to find out what ``foo`` possibly
|
||||||
is.
|
is.
|
||||||
"""
|
"""
|
||||||
function_value.inference_state
|
|
||||||
funcdef = function_value.tree_node
|
funcdef = function_value.tree_node
|
||||||
|
|
||||||
if not settings.dynamic_params:
|
if not settings.dynamic_params:
|
||||||
return create_default_params(function_value, funcdef)
|
return NO_VALUES
|
||||||
|
|
||||||
function_value.inference_state.dynamic_params_depth += 1
|
path = function_value.get_root_context().py__file__()
|
||||||
try:
|
if path is not None and is_stdlib_path(path):
|
||||||
path = function_value.get_root_context().py__file__()
|
# We don't want to search for usages in the stdlib. Usually people
|
||||||
if path is not None and is_stdlib_path(path):
|
# don't work with it (except if you are a core maintainer, sorry).
|
||||||
# We don't want to search for usages in the stdlib. Usually people
|
# This makes everything slower. Just disable it and run the tests,
|
||||||
# don't work with it (except if you are a core maintainer, sorry).
|
# you will see the slowdown, especially in 3.6.
|
||||||
# This makes everything slower. Just disable it and run the tests,
|
return NO_VALUES
|
||||||
# you will see the slowdown, especially in 3.6.
|
|
||||||
return create_default_params(function_value, funcdef)
|
|
||||||
|
|
||||||
if funcdef.type == 'lambdef':
|
if funcdef.type == 'lambdef':
|
||||||
string_name = _get_lambda_name(funcdef)
|
string_name = _get_lambda_name(funcdef)
|
||||||
if string_name is None:
|
if string_name is None:
|
||||||
return create_default_params(function_value, funcdef)
|
return NO_VALUES
|
||||||
else:
|
else:
|
||||||
string_name = funcdef.name.value
|
string_name = funcdef.name.value
|
||||||
debug.dbg('Dynamic param search in %s.', string_name, color='MAGENTA')
|
debug.dbg('Dynamic param search in %s.', string_name, color='MAGENTA')
|
||||||
|
|
||||||
try:
|
module_context = function_value.get_root_context()
|
||||||
module_context = function_value.get_root_context()
|
arguments_list = _search_function_arguments(
|
||||||
arguments_list = _search_function_arguments(
|
module_context,
|
||||||
module_context,
|
funcdef,
|
||||||
funcdef,
|
string_name=string_name,
|
||||||
string_name=string_name,
|
)
|
||||||
)
|
if arguments_list:
|
||||||
if arguments_list:
|
return ValueSet.from_sets(
|
||||||
zipped_param_names = zip(*list(
|
get_executed_param_names(
|
||||||
get_executed_param_names(function_value, arguments)
|
function_value, arguments
|
||||||
for arguments in arguments_list
|
)[param_index].infer()
|
||||||
))
|
for arguments in arguments_list
|
||||||
params = [DynamicExecutedParamName(executed_param_names)
|
)
|
||||||
for executed_param_names in zipped_param_names]
|
else:
|
||||||
else:
|
return NO_VALUES
|
||||||
return create_default_params(function_value, funcdef)
|
debug.dbg('Dynamic param result finished', color='MAGENTA')
|
||||||
finally:
|
|
||||||
debug.dbg('Dynamic param result finished', color='MAGENTA')
|
|
||||||
return params
|
|
||||||
finally:
|
|
||||||
function_value.inference_state.dynamic_params_depth -= 1
|
|
||||||
|
|
||||||
|
|
||||||
@inference_state_method_cache(default=None)
|
@inference_state_method_cache(default=None)
|
||||||
|
|||||||
@@ -332,9 +332,23 @@ class SimpleParamName(X):
|
|||||||
if values:
|
if values:
|
||||||
return values
|
return values
|
||||||
# TODO private access
|
# TODO private access
|
||||||
from jedi.inference.dynamic_params import search_param_names
|
from jedi.inference.dynamic_params import dynamic_param_lookup
|
||||||
param_names = search_param_names(self.function_value)
|
param = self._get_param_node()
|
||||||
return param_names[self._get_param_node().position_index].infer()
|
values = dynamic_param_lookup(self.function_value, param.position_index)
|
||||||
|
if values:
|
||||||
|
return values
|
||||||
|
|
||||||
|
if param.star_count == 1:
|
||||||
|
from jedi.inference.value.iterable import FakeTuple
|
||||||
|
value = FakeTuple(self.function_value.inference_state, [])
|
||||||
|
elif param.star_count == 2:
|
||||||
|
from jedi.inference.value.iterable import FakeDict
|
||||||
|
value = FakeDict(self.function_value.inference_state, {})
|
||||||
|
elif param.default is None:
|
||||||
|
return NO_VALUES
|
||||||
|
else:
|
||||||
|
return self.function_value.parent_context.infer_node(param.default)
|
||||||
|
return ValueSet({value})
|
||||||
|
|
||||||
|
|
||||||
class ParamName(X):
|
class ParamName(X):
|
||||||
|
|||||||
@@ -219,24 +219,3 @@ def _error_argument_count(funcdef, actual_count):
|
|||||||
before = 'from %s to ' % (len(params) - default_arguments)
|
before = 'from %s to ' % (len(params) - default_arguments)
|
||||||
return ('TypeError: %s() takes %s%s arguments (%s given).'
|
return ('TypeError: %s() takes %s%s arguments (%s given).'
|
||||||
% (funcdef.name, before, len(params), actual_count))
|
% (funcdef.name, before, len(params), actual_count))
|
||||||
|
|
||||||
|
|
||||||
def _create_default_param(function_value, arguments, param):
|
|
||||||
if param.star_count == 1:
|
|
||||||
result_arg = LazyKnownValue(
|
|
||||||
iterable.FakeTuple(function_value.inference_state, [])
|
|
||||||
)
|
|
||||||
elif param.star_count == 2:
|
|
||||||
result_arg = LazyKnownValue(
|
|
||||||
iterable.FakeDict(function_value.inference_state, {})
|
|
||||||
)
|
|
||||||
elif param.default is None:
|
|
||||||
result_arg = LazyUnknownValue()
|
|
||||||
else:
|
|
||||||
result_arg = LazyTreeValue(function_value.parent_context, param.default)
|
|
||||||
return ExecutedParamName(function_value, arguments, param, result_arg)
|
|
||||||
|
|
||||||
|
|
||||||
def create_default_params(function_value, funcdef):
|
|
||||||
return [_create_default_param(function_value, None, p)
|
|
||||||
for p in funcdef.get_params()]
|
|
||||||
|
|||||||
Reference in New Issue
Block a user