diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 3f0a22d0..29e94540 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -256,6 +256,13 @@ class Evaluator(object): new_types += get(self, node) return new_types + def execute_evaluated(self, obj, *args): + """ + Execute a function with already executed arguments. + """ + args = [iterable.AlreadyEvaluated([arg]) for arg in args] + return self.execute(obj, args) + @debug.increase_indent def execute(self, obj, arguments=(), trailer=None): if not isinstance(arguments, param.Arguments): diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 7b462d75..ca97c4c3 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -20,6 +20,7 @@ It works as follows: from jedi._compatibility import unicode from jedi.parser import representation as pr from jedi import settings +from jedi import debug from jedi.evaluate import helpers from jedi.evaluate.cache import memoize_default from jedi.evaluate import imports @@ -40,6 +41,7 @@ class ParamListener(object): self.param_possibilities.append(params) +@debug.increase_indent @memoize_default([], evaluator_is_first_arg=True) def search_params(evaluator, param): """ @@ -57,6 +59,7 @@ def search_params(evaluator, param): if not settings.dynamic_params: return [] from jedi.evaluate import representation as er + debug.dbg('Dynamic param search for %s', param) def get_params_for_module(module): """ @@ -71,7 +74,7 @@ def search_params(evaluator, param): for name in names: stmt = name.get_definition() - if not isinstance(stmt, (pr.ExprStmt, pr.CompFor)): + if not isinstance(stmt, (pr.ExprStmt, pr.CompFor, pr.ReturnStmt)): continue parent = name.parent if pr.is_node(parent, 'trailer'): @@ -179,4 +182,5 @@ def search_params(evaluator, param): # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) + debug.dbg('Dynamic param result %s', result) return result diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index cfd4b11e..3eb25bd4 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -211,14 +211,14 @@ class NameFinder(object): # str is important, because it shouldn't be `Name`! name = compiled.create(self._evaluator, str(self.name_str)) with common.ignored(KeyError): - result = inst.execute_subscope_by_name('__getattr__', [name]) + result = inst.execute_subscope_by_name('__getattr__', name) if not result: # this is a little bit special. `__getattribute__` is executed # before anything else. But: I know no use case, where this # could be practical and the jedi would return wrong types. If # you ever have something, let me know! with common.ignored(KeyError): - result = inst.execute_subscope_by_name('__getattribute__', [name]) + result = inst.execute_subscope_by_name('__getattribute__', name) return result def _is_name_break_scope(self, stmt): diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index e2b0809f..f048061b 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -200,7 +200,7 @@ def get_params(evaluator, func, var_args): from jedi.evaluate.representation import InstanceElement if isinstance(func, InstanceElement): # Include self at this place. - unpacked_va.insert(0, (None, [func.instance])) + unpacked_va.insert(0, (None, [iterable.AlreadyEvaluated([func.instance])])) var_arg_iterator = common.PushBackIterator(iter(unpacked_va)) non_matching_keys = defaultdict(lambda: []) @@ -289,6 +289,7 @@ def get_params(evaluator, func, var_args): result.append(_gen_param_name_copy(evaluator, func, var_args, param, [], values)) + if not (non_matching_keys or had_multiple_value_error or param.stars or param.default): # add a warning only if there's not another one. diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index b4ca22c2..f4cdb885 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -97,8 +97,12 @@ class Instance(use_metaclass(CachedMetaClass, Executed)): else: # Need to execute the __init__ function, because the dynamic param # searching needs it. - with common.ignored(KeyError): - self.execute_subscope_by_name('__init__', self.var_args) + try: + method = self.get_subscope_by_name('__init__') + except KeyError: + pass + else: + evaluator.execute(method, self.var_args) # Generated instances are classes that are just generated by self # (No var_args) used. self.is_generated = is_generated @@ -180,16 +184,16 @@ class Instance(use_metaclass(CachedMetaClass, Executed)): sub = self.base.get_subscope_by_name(name) return get_instance_el(self._evaluator, self, sub, True) - def execute_subscope_by_name(self, name, args=()): + def execute_subscope_by_name(self, name, *args): method = self.get_subscope_by_name(name) - return self._evaluator.execute(method, args) + return self._evaluator.execute_evaluated(method, *args) def get_descriptor_return(self, obj): """ Throws a KeyError if there's no method. """ # Arguments in __get__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. args = [obj, obj.base] if isinstance(obj, Instance) else [compiled.none_obj, obj] - return self.execute_subscope_by_name('__get__', args) + return self.execute_subscope_by_name('__get__', *args) def scope_names_generator(self, position=None): """ @@ -211,7 +215,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)): indexes = [] try: - return self.execute_subscope_by_name('__getitem__', [indexes]) + return self.execute_subscope_by_name('__getitem__', indexes) except KeyError: debug.warning('No __getitem__, cannot access the array.') return [] @@ -494,8 +498,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)): # Create param array. old_func = Function(self._evaluator, f, is_decorated=True) - arg = iterable.AlreadyEvaluated([old_func]) - wrappers = self._evaluator.execute(decorator, (arg,)) + wrappers = self._evaluator.execute_evaluated(decorator, old_func) if not len(wrappers): debug.warning('no wrappers found %s', self.base_func) return self diff --git a/test/completion/functions.py b/test/completion/functions.py index d333657f..48a5331b 100644 --- a/test/completion/functions.py +++ b/test/completion/functions.py @@ -358,11 +358,13 @@ def nested_kw(**kwargs1): def nested_kw2(**kwargs2): return nested_kw(**kwargs2) -#? int() +# invalid command, doesn't need to return anything +#? nested_kw(b=1, c=1.0, list) #? int() nested_kw(b=1) -#? int() +# invalid command, doesn't need to return anything +#? nested_kw(d=1.0, b=1, list) #? int() nested_kw(a=3.0, b=1) @@ -395,10 +397,12 @@ def nested_both(*args, **kwargs): def nested_both2(*args, **kwargs): return nested_both(*args, **kwargs) -#? int() +# invalid commands, may return whatever. +#? list nested_both('', b=1, c=1.0, list) -#? int() +#? list nested_both('', c=1.0, b=1, list) + #? [] nested_both('')