mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-16 02:27:06 +08:00
Function for evaluating functions with already executed arguments.
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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('')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user