diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 39c2fa61..6bde42b7 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -75,7 +75,6 @@ from jedi.evaluate import imports from jedi.evaluate import recursion from jedi.evaluate import iterable from jedi.evaluate.cache import evaluator_function_cache -from jedi.evaluate import stdlib from jedi.evaluate import compiled from jedi.evaluate import helpers from jedi.evaluate.filters import TreeNameDefinition, ParamName @@ -202,29 +201,6 @@ class Evaluator(object): def _eval_element_cached(self, context, element): return eval_node(context, element) - @debug.increase_indent - def execute(self, obj, arguments): - if self.is_analysis: - arguments.eval_all() - - debug.dbg('execute: %s %s', obj, arguments) - try: - # Some stdlib functions like super(), namedtuple(), etc. have been - # hard-coded in Jedi to support them. - return stdlib.execute(self, obj, arguments) - except stdlib.NotInStdLib: - pass - - try: - func = obj.py__call__ - except AttributeError: - debug.warning("no execution possible %s", obj) - return NO_CONTEXTS - else: - context_set = func(arguments) - debug.dbg('execute result: %s in %s', context_set, obj) - return context_set - def goto_definitions(self, context, name): def_ = name.get_definition(import_name_always=True) if def_ is not None: diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index ab9ea8f5..56faef5b 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -266,7 +266,7 @@ class CompiledObject(Context): # TODO do we? continue bltn_obj = create(self.evaluator, bltn_obj) - for result in self.evaluator.execute(bltn_obj, params): + for result in bltn_obj.execute(params): yield result for type_ in docstrings.infer_return_types(self): yield type_ diff --git a/jedi/evaluate/context.py b/jedi/evaluate/context.py index 117b189d..9d62a51b 100644 --- a/jedi/evaluate/context.py +++ b/jedi/evaluate/context.py @@ -1,5 +1,7 @@ -from jedi._compatibility import Python3Method from parso.python.tree import ExprStmt, CompFor + +from jedi import debug +from jedi._compatibility import Python3Method from jedi.parser_utils import clean_scope_docstring, get_doc_with_call_signature from jedi.common import BaseContextSet @@ -32,7 +34,36 @@ class Context(object): return context context = context.parent_context + @debug.increase_indent def execute(self, arguments): + """ + In contrast to py__call__ this function is always available. + + `hasattr(x, py__call__)` can also be checked to see if a context is + executable. + """ + if self.evaluator.is_analysis: + arguments.eval_all() + + debug.dbg('execute: %s %s', self, arguments) + from jedi.evaluate import stdlib + try: + # Some stdlib functions like super(), namedtuple(), etc. have been + # hard-coded in Jedi to support them. + return stdlib.execute(self.evaluator, self, arguments) + except stdlib.NotInStdLib: + pass + + try: + func = self.py__call__ + except AttributeError: + debug.warning("no execution possible %s", self) + return NO_CONTEXTS + else: + context_set = func(arguments) + debug.dbg('execute result: %s in %s', context_set, self) + return context_set + return self.evaluator.execute(self, arguments) def execute_evaluated(self, *value_list): diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index 9e7fec4c..bb9a65f1 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -35,7 +35,7 @@ from jedi.evaluate.cache import evaluator_method_cache from jedi.evaluate.filters import DictFilter, AbstractNameDefinition, \ ParserTreeFilter from jedi.evaluate import context -from jedi.evaluate.context import ContextSet, NO_CONTEXTS +from jedi.evaluate.context import ContextSet, NO_CONTEXTS, Context from jedi.parser_utils import get_comp_fors @@ -54,22 +54,20 @@ class AbstractSequence(context.Context): return compiled.CompiledContextName(self, self.array_type) -class BuiltinMethod(object): +class BuiltinMethod(Context): """``Generator.__next__`` ``dict.values`` methods and so on.""" + api_type = 'function' + def __init__(self, builtin_context, method, builtin_func): - self._builtin_context = builtin_context + super(BuiltinMethod, self).__init__( + builtin_context.evaluator, + parent_context=builtin_context + ) self._method = method self._builtin_func = builtin_func - # TODO it seems kind of stupid that we have to overwrite 3 methods here. def py__call__(self, params): - return self._method(self._builtin_context) - - def execute(self, *args, **kwargs): - return self._builtin_context.evaluator.execute(self, *args, **kwargs) - - def execute_evaluated(self, *args, **kwargs): - return self._builtin_context.evaluator.execute_evaluated(self, *args, **kwargs) + return self._method(self.parent_context) def __getattr__(self, name): return getattr(self._builtin_func, name)