Refactor the dynamic params functionality.

This commit is contained in:
Dave Halter
2016-07-17 19:05:47 +02:00
parent 75c1ebc2fe
commit becbbb2e64
+34 -44
View File
@@ -79,52 +79,29 @@ def search_function_call(evaluator, func):
""" """
from jedi.evaluate import representation as er from jedi.evaluate import representation as er
def get_params_for_module(module): def get_possible_nodes(module, func_name):
"""
Returns the values of a param, or an empty array.
"""
@memoize_default([], evaluator_is_first_arg=True)
def get_posibilities(evaluator, module, func_name):
try: try:
names = module.used_names[func_name] names = module.used_names[func_name]
except KeyError: except KeyError:
return [] return
for name in names: for name in names:
parent = name.parent bracket = name.get_next_leaf()
if tree.is_node(parent, 'trailer'): trailer = bracket.parent
parent = parent.parent if trailer.type == 'trailer' and bracket == '(':
yield name, trailer
trailer = None def undecorate(typ):
if tree.is_node(parent, 'power', 'atom_expr'): # We have to remove decorators, because they are not the
for t in parent.children[1:]: # "original" functions, this way we can easily compare.
if t == '**': # At the same time we also have to remove InstanceElements.
break if typ.isinstance(er.Function, er.Instance) \
if t.start_pos > name.start_pos and t.children[0] == '(': and typ.decorates is not None:
trailer = t return typ.decorates
break elif isinstance(typ, er.InstanceElement):
if trailer is not None: return typ.var
types = evaluator.goto_definitions(name) else:
return typ
# We have to remove decorators, because they are not the
# "original" functions, this way we can easily compare.
# At the same time we also have to remove InstanceElements.
undec = []
for escope in types:
if escope.isinstance(er.Function, er.Instance) \
and escope.decorates is not None:
undec.append(escope.decorates)
elif isinstance(escope, er.InstanceElement):
undec.append(escope.var)
else:
undec.append(escope)
if evaluator.wrap(compare) in undec:
# Only if we have the correct function we execute
# it, otherwise just ignore it.
evaluator.eval_trailer(types, trailer)
return listener.param_possibilities
return get_posibilities(evaluator, module, func_name)
current_module = func.get_parent_until() current_module = func.get_parent_until()
func_name = unicode(func.name) func_name = unicode(func.name)
@@ -141,13 +118,26 @@ def search_function_call(evaluator, func):
try: try:
result = [] result = []
# This is like backtracking: Get the first possible result. i = 0
for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name): for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name):
result = get_params_for_module(mod) for name, trailer in get_possible_nodes(mod, func_name):
i += 1
for typ in evaluator.goto_definitions(name):
undecorated = undecorate(typ)
if evaluator.wrap(compare) == undecorated:
# Only if we have the correct function we execute
# it, otherwise just ignore it.
evaluator.eval_trailer([typ], trailer)
result = listener.param_possibilities
# If there are results after processing a module, we're probably
# good to process.
if result: if result:
break return result
finally: finally:
# cleanup: remove the listener; important: should not stick. # cleanup: remove the listener; important: should not stick.
func.listeners.remove(listener) func.listeners.remove(listener)
return result return set()