diff --git a/jedi/evaluate/docstrings.py b/jedi/evaluate/docstrings.py index 39121909..0331f6e0 100644 --- a/jedi/evaluate/docstrings.py +++ b/jedi/evaluate/docstrings.py @@ -189,7 +189,7 @@ def _execute_array_values(evaluator, array): @evaluator_method_cache() def infer_param(execution_context, param): - from jedi.evaluate.instance import InstanceFunctionExecution + from jedi.evaluate.instance import AnonymousInstanceFunctionExecution def eval_docstring(docstring): return set( @@ -203,7 +203,7 @@ def infer_param(execution_context, param): return set() types = eval_docstring(execution_context.py__doc__()) - if isinstance(execution_context, InstanceFunctionExecution) and \ + if isinstance(execution_context, AnonymousInstanceFunctionExecution) and \ execution_context.function_context.name.string_name == '__init__': class_context = execution_context.instance.class_context types |= eval_docstring(class_context.py__doc__()) diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index e6f9012d..00c38f51 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -22,7 +22,7 @@ from jedi import settings from jedi import debug from jedi.evaluate.cache import evaluator_function_cache from jedi.evaluate import imports -from jedi.evaluate.param import TreeArguments, create_default_param +from jedi.evaluate.param import TreeArguments, create_default_params from jedi.evaluate.helpers import is_stdlib_path from jedi.common import to_list, unite from jedi.parser_utils import get_parent_scope @@ -68,7 +68,7 @@ def search_params(evaluator, execution_context, funcdef): is. """ if not settings.dynamic_params: - return [] + return create_default_params(execution_context, funcdef) evaluator.dynamic_params_depth += 1 try: @@ -78,7 +78,7 @@ def search_params(evaluator, execution_context, funcdef): # don't work with it (except if you are a core maintainer, sorry). # This makes everything slower. Just disable it and run the tests, # you will see the slowdown, especially in 3.6. - return [] + return create_default_params(execution_context, funcdef) debug.dbg('Dynamic param search in %s.', funcdef.name.value, color='MAGENTA') @@ -96,7 +96,7 @@ def search_params(evaluator, execution_context, funcdef): params = [MergedExecutedParams(executed_params) for executed_params in zipped_params] # Evaluate the ExecutedParams to types. else: - params = [create_default_param(execution_context, p) for p in funcdef.get_params()] + return create_default_params(execution_context, funcdef) debug.dbg('Dynamic param result finished', color='MAGENTA') return params finally: diff --git a/jedi/evaluate/instance.py b/jedi/evaluate/instance.py index 4f0550df..07cf6f20 100644 --- a/jedi/evaluate/instance.py +++ b/jedi/evaluate/instance.py @@ -7,6 +7,7 @@ from jedi.evaluate import compiled from jedi.evaluate import filters from jedi.evaluate.context import Context, LazyKnownContext, LazyKnownContexts from jedi.evaluate.cache import evaluator_method_cache +from jedi.evaluate.param import AbstractArguments, AnonymousArguments from jedi.cache import memoize_method from jedi.evaluate import representation as er from jedi.evaluate.dynamic import search_params @@ -14,11 +15,31 @@ from jedi.evaluate import iterable from jedi.parser_utils import get_parent_scope + +class InstanceFunctionExecution(er.FunctionExecutionContext): + def __init__(self, instance, parent_context, function_context, var_args): + self.instance = instance + var_args = InstanceVarArgs(self, function_context.tree_node, var_args) + + super(InstanceFunctionExecution, self).__init__( + instance.evaluator, parent_context, function_context, var_args) + + +class AnonymousInstanceFunctionExecution(er.FunctionExecutionContext): + function_execution_filter = filters.AnonymousInstanceFunctionExecutionFilter + + def __init__(self, instance, parent_context, function_context, var_args): + self.instance = instance + super(AnonymousInstanceFunctionExecution, self).__init__( + instance.evaluator, parent_context, function_context, var_args) + + class AbstractInstanceContext(Context): """ This class is used to evaluate instances. """ api_type = 'instance' + function_execution_cls = InstanceFunctionExecution def __init__(self, evaluator, parent_context, class_context, var_args): super(AbstractInstanceContext, self).__init__(evaluator, parent_context) @@ -136,7 +157,7 @@ class AbstractInstanceContext(Context): bound_method = BoundMethod( self.evaluator, self, class_context, self.parent_context, func_node ) - return InstanceFunctionExecution( + return self.function_execution_cls( self, class_context.parent_context, bound_method, @@ -208,12 +229,14 @@ class TreeInstance(AbstractInstanceContext): class AnonymousInstance(TreeInstance): + function_execution_cls = AnonymousInstanceFunctionExecution + def __init__(self, evaluator, parent_context, class_context): super(AnonymousInstance, self).__init__( evaluator, parent_context, class_context, - var_args=None + var_args=AnonymousArguments(self), ) @@ -264,8 +287,9 @@ class BoundMethod(er.FunctionContext): def get_function_execution(self, arguments=None): if arguments is None: + arguments = AnonymousArguments(self) return AnonymousInstanceFunctionExecution( - self._instance, self.parent_context, self) + self._instance, self.parent_context, self, arguments) else: return InstanceFunctionExecution( self._instance, self.parent_context, self, arguments) @@ -411,7 +435,7 @@ class ParamArguments(object): return [] -class InstanceVarArgs(object): +class InstanceVarArgs(AbstractArguments): def __init__(self, execution_context, funcdef, var_args): self._execution_context = execution_context self._funcdef = funcdef @@ -419,12 +443,16 @@ class InstanceVarArgs(object): @memoize_method def _get_var_args(self): - if self._var_args is None: - # TODO this parent_context might be wrong. test?! - return ParamArguments(self._execution_context, self._funcdef) - return self._var_args + @property + def argument_node(self): + return self._var_args.argument_node + + @property + def trailer(self): + return self._var_args.trailer + def unpack(self, func=None): yield None, LazyKnownContext(self._execution_context.instance) for values in self._get_var_args().unpack(func): @@ -432,23 +460,3 @@ class InstanceVarArgs(object): def get_calling_nodes(self): return self._get_var_args().get_calling_nodes() - - def __getattr__(self, name): - return getattr(self._var_args, name) - - -class InstanceFunctionExecution(er.FunctionExecutionContext): - def __init__(self, instance, parent_context, function_context, var_args): - self.instance = instance - var_args = InstanceVarArgs(self, function_context.tree_node, var_args) - - super(InstanceFunctionExecution, self).__init__( - instance.evaluator, parent_context, function_context, var_args) - - -class AnonymousInstanceFunctionExecution(InstanceFunctionExecution): - function_execution_filter = filters.AnonymousInstanceFunctionExecutionFilter - - def __init__(self, instance, parent_context, function_context): - super(AnonymousInstanceFunctionExecution, self).__init__( - instance, parent_context, function_context, None) diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index 680614e1..22a9cdd3 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -73,6 +73,22 @@ class AbstractArguments(): def get_calling_nodes(self): raise NotImplementedError + def unpack(self, funcdef=None): + raise NotImplementedError + + def get_params(self, execution_context): + return get_params(execution_context, self) + + + +class AnonymousArguments(AbstractArguments): + def __init__(self, anonymous_context): + self.context = anonymous_context + + def get_params(self, execution_context): + from jedi.evaluate.dynamic import search_params + return search_params(self.context.evaluator, execution_context, execution_context.tree_node) + class TreeArguments(AbstractArguments): def __init__(self, evaluator, context, argument_node, trailer=None): @@ -191,6 +207,7 @@ class TreeArguments(AbstractArguments): arguments = param.var_args break + print(arguments) return [arguments.argument_node or arguments.trailer] @@ -395,7 +412,7 @@ def _error_argument_count(funcdef, actual_count): % (funcdef.name, before, len(params), actual_count)) -def create_default_param(execution_context, param): +def _create_default_param(execution_context, param): if param.star_count == 1: result_arg = context.LazyKnownContext( iterable.FakeSequence(execution_context.evaluator, 'tuple', []) @@ -409,3 +426,9 @@ def create_default_param(execution_context, param): else: result_arg = context.LazyTreeContext(execution_context.parent_context, param.default) return ExecutedParam(execution_context, param, result_arg) + + +def create_default_params(execution_context, funcdef): + return [_create_default_param(execution_context, p) + for p in funcdef.get_params()] + diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 2e42b26d..bc053d4f 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -62,7 +62,6 @@ from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \ GlobalNameFilter, DictFilter, ContextName, AbstractNameDefinition, \ ParamName, AnonymousInstanceParamName, TreeNameDefinition, \ ContextNameMixin -from jedi.evaluate.dynamic import search_params from jedi.evaluate import context from jedi.evaluate.context import ContextualizedNode from jedi import parser_utils @@ -418,18 +417,15 @@ class FunctionExecutionContext(context.TreeContext): @evaluator_method_cache() def get_params(self): - return param.get_params(self, self.var_args) + return self.var_args.get_params(self) class AnonymousFunctionExecution(FunctionExecutionContext): def __init__(self, evaluator, parent_context, function_context): super(AnonymousFunctionExecution, self).__init__( - evaluator, parent_context, function_context, var_args=None) - - @evaluator_method_cache() - def get_params(self): - # We need to do a dynamic search here. - return search_params(self.evaluator, self, self.tree_node) + evaluator, parent_context, function_context, + var_args=param.AnonymousArguments(self) + ) class ModuleAttributeName(AbstractNameDefinition): diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index 679a55c4..84bd3335 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -16,7 +16,8 @@ from jedi.common import unite from jedi.evaluate import compiled from jedi.evaluate import representation as er from jedi.evaluate.instance import InstanceFunctionExecution, \ - AbstractInstanceContext, CompiledInstance, BoundMethod + AbstractInstanceContext, CompiledInstance, BoundMethod, \ + AnonymousInstanceFunctionExecution from jedi.evaluate import iterable from jedi import debug from jedi.evaluate import precedence @@ -163,7 +164,8 @@ class SuperInstance(AbstractInstanceContext): @argument_clinic('[type[, obj]], /', want_context=True) def builtins_super(evaluator, types, objects, context): # TODO make this able to detect multiple inheritance super - if isinstance(context, InstanceFunctionExecution): + if isinstance(context, (InstanceFunctionExecution, + AnonymousInstanceFunctionExecution)): su = context.instance.py__class__().py__bases__() return unite(context.execute_evaluated() for context in su[0].infer()) return set()