def usages(module_context, tree_name): search_name = tree_name.value found_names = _find_names(module_context, tree_name) modules = set(d.get_root_context() for d in found_names.values()) modules = set(m for m in modules if isinstance(m, ModuleContext)) non_matching_usage_maps = {} for m in imports.get_modules_containing_name(module_context.evaluator, modules, search_name): for name_leaf in m.tree_node.get_used_names().get(search_name, []): new = _find_names(m, name_leaf) if any(tree_name in found_names for tree_name in new): found_names.update(new) for tree_name in new: for dct in non_matching_usage_maps.get(tree_name, []): # A usage that was previously searched for matches with # a now found name. Merge. found_names.update(dct) try: del non_matching_usage_maps[tree_name] except KeyError: pass else: for name in new: non_matching_usage_maps.setdefault(name, []).append(new) return found_names.values()
def usages(module_context, tree_name): search_name = tree_name.value found_names = _find_names(module_context, tree_name) modules = set(d.get_root_context() for d in found_names.values()) modules = set(m for m in modules if isinstance(m, ModuleContext)) non_matching_usage_maps = {} for m in imports.get_modules_containing_name(module_context.evaluator, modules, search_name): for name_leaf in m.tree_node.get_used_names().get(search_name, []): new = _find_names(m, name_leaf) if any(tree_name in found_names for tree_name in new): found_names.update(new) for tree_name in new: for dct in non_matching_usage_maps.get(tree_name, []): # A usage that was previously searched for matches with # a now found name. Merge. found_names.update(dct) try: del non_matching_usage_maps[tree_name] except KeyError: pass else: for name in new: non_matching_usage_maps.setdefault(name, []).append(new) return found_names.values()
def usages(evaluator, definition_names, mods): """ :param definitions: list of Name """ def compare_array(definitions): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ result = [] for d in definitions: module = d.get_parent_until() result.append((module, d.start_pos)) return result search_name = unicode(list(definition_names)[0]) compare_definitions = compare_array(definition_names) mods |= set([d.get_parent_until() for d in definition_names]) definitions = [] for m in imports.get_modules_containing_name(evaluator, mods, search_name): try: check_names = m.used_names[search_name] except KeyError: continue for name in check_names: result = evaluator.goto(name) if [c for c in compare_array(result) if c in compare_definitions]: definitions.append(classes.Definition(evaluator, name)) # Previous definitions might be imports, so include them # (because goto might return that import name). compare_definitions += compare_array([name]) return definitions
def test_get_modules_containing_name(evaluator, path, goal, is_package): module = imports._load_python_module( evaluator, FileIO(path), import_names=('ok', 'lala', 'x'), is_package=is_package, ) assert module input_module, found_module = imports.get_modules_containing_name( evaluator, [module], 'string_that_only_exists_here') assert input_module is module assert found_module.string_names == goal
def usages(evaluator, definition_names, mods): """ :param definitions: list of Name """ def resolve_names(definition_names): for name in definition_names: if name.api_type == 'module': found = False for context in name.infer(): found = True yield context.name if not found: yield name else: yield name def compare_array(definition_names): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ return [(name.get_root_context(), name.start_pos) for name in resolve_names(definition_names)] search_name = list(definition_names)[0].string_name compare_definitions = compare_array(definition_names) mods = mods | set([d.get_root_context() for d in definition_names]) definition_names = set(resolve_names(definition_names)) for m in imports.get_modules_containing_name(evaluator, mods, search_name): if isinstance(m, ModuleContext): for name_node in m.tree_node.used_names.get(search_name, []): context = evaluator.create_context(m, name_node) try: result = evaluator.goto(context, name_node) except (NotImplementedError, RecursionError) as err: logger.error(err) continue if any( compare_contexts(c1, c2) for c1 in compare_array(result) for c2 in compare_definitions): name = TreeNameDefinition(context, name_node) definition_names.add(name) # Previous definitions might be imports, so include them # (because goto might return that import name). compare_definitions += compare_array([name]) else: # compiled objects definition_names.add(m.name) return [classes.Definition(evaluator, n) for n in definition_names]
def usages(evaluator, definition_names, mods): """ :param definitions: list of Name """ def resolve_names(definition_names): for name in definition_names: if name.api_type == 'module': found = False for context in name.infer(): if isinstance(context, ModuleContext): found = True yield context.name if not found: yield name else: yield name def compare_array(definition_names): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ return [ (name.get_root_context(), name.start_pos) for name in resolve_names(definition_names) ] search_name = list(definition_names)[0].string_name compare_definitions = compare_array(definition_names) mods = mods | set([d.get_root_context() for d in definition_names]) definition_names = set(resolve_names(definition_names)) for m in imports.get_modules_containing_name(evaluator, mods, search_name): if isinstance(m, ModuleContext): for name_node in m.tree_node.used_names.get(search_name, []): context = evaluator.create_context(m, name_node) result = evaluator.goto(context, name_node) if any(compare_contexts(c1, c2) for c1 in compare_array(result) for c2 in compare_definitions): name = TreeNameDefinition(context, name_node) definition_names.add(name) # Previous definitions might be imports, so include them # (because goto might return that import name). compare_definitions += compare_array([name]) else: # compiled objects definition_names.add(m.name) return [classes.Definition(evaluator, n) for n in definition_names]
def _search_function_executions(evaluator, module_context, funcdef): """ Returns a list of param names. """ from jedi.evaluate import representation as er func_string_name = funcdef.name.value compare_node = funcdef if func_string_name == '__init__': cls = funcdef.get_parent_scope() if isinstance(cls, tree.Class): func_string_name = cls.name.value compare_node = cls found_executions = False i = 0 for for_mod_context in imports.get_modules_containing_name( evaluator, [module_context], func_string_name): if not isinstance(module_context, er.ModuleContext): return for name, trailer in _get_possible_nodes(for_mod_context, func_string_name): i += 1 # This is a simple way to stop Jedi's dynamic param recursion # from going wild: The deeper Jedi's in the recursion, the less # code should be evaluated. if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES: return random_context = evaluator.create_context(for_mod_context, name) for function_execution in _check_name_for_execution( evaluator, random_context, compare_node, name, trailer): found_executions = True yield function_execution # If there are results after processing a module, we're probably # good to process. This is a speed optimization. if found_executions: return
def _search_function_executions(evaluator, module_context, funcdef): """ Returns a list of param names. """ from jedi.evaluate import representation as er func_string_name = funcdef.name.value compare_node = funcdef if func_string_name == '__init__': cls = funcdef.get_parent_scope() if isinstance(cls, tree.Class): func_string_name = cls.name.value compare_node = cls found_executions = False i = 0 for for_mod_context in imports.get_modules_containing_name( evaluator, [module_context], func_string_name): if not isinstance(module_context, er.ModuleContext): return for name, trailer in _get_possible_nodes(for_mod_context, func_string_name): i += 1 # This is a simple way to stop Jedi's dynamic param recursion # from going wild: The deeper Jedi's in the recursion, the less # code should be evaluated. if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES: return random_context = evaluator.create_context(for_mod_context, name) for function_execution in _check_name_for_execution( evaluator, random_context, compare_node, name, trailer): found_executions = True yield function_execution # If there are results after processing a module, we're probably # good to process. This is a speed optimization. if found_executions: return
def search_function_call(evaluator, func): """ Returns a list of param names. """ from jedi.evaluate import representation as er def get_possible_nodes(module, func_name): try: names = module.used_names[func_name] except KeyError: return for name in names: bracket = name.get_next_leaf() trailer = bracket.parent if trailer.type == 'trailer' and bracket == '(': yield name, trailer def undecorate(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. if typ.isinstance(er.Function, er.Instance) \ and typ.decorates is not None: return typ.decorates elif isinstance(typ, er.InstanceElement): return typ.var else: return typ current_module = func.get_parent_until() func_name = unicode(func.name) compare = func if func_name == '__init__': cls = func.get_parent_scope() if isinstance(cls, tree.Class): func_name = unicode(cls.name) compare = cls # add the listener listener = ParamListener() func.listeners.add(listener) try: result = [] i = 0 for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name): for name, trailer in get_possible_nodes(mod, func_name): i += 1 # This is a simple way to stop Jedi's dynamic param recursion # from going wild: The deeper Jedi's in the recursin, the less # code should be evaluated. if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES: return listener.param_possibilities 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: return result finally: # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) return set()
def search_params(evaluator, param): """ This is a dynamic search for params. If you try to complete a type: >>> def func(foo): ... foo >>> func(1) >>> func("") It is not known what the type is, because it cannot be guessed with recursive madness. Therefore one has to analyse the statements that are calling the function, as well as analyzing the incoming params. """ if not settings.dynamic_params: return [] def get_params_for_module(module): """ 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: possible_stmts = module.used_names[func_name] except KeyError: return [] for stmt in possible_stmts: if isinstance(stmt, pr.Import): continue calls = helpers.scan_statement_for_calls(stmt, func_name) for c in calls: # no execution means that params cannot be set call_path = list(c.generate_call_path()) pos = c.start_pos scope = stmt.parent # this whole stuff is just to not execute certain parts # (speed improvement), basically we could just call # ``eval_call_path`` on the call_path and it would # also work. def listRightIndex(lst, value): return len(lst) - lst[-1::-1].index(value) - 1 # Need to take right index, because there could be a # func usage before. i = listRightIndex(call_path, func_name) first, last = call_path[:i], call_path[i + 1:] if not last and not call_path.index(func_name) != i: continue scopes = [scope] if first: scopes = evaluator.eval_call_path( iter(first), scope, pos) pos = None from jedi.evaluate import representation as er for scope in scopes: s = evaluator.find_types(scope, func_name, position=pos, search_global=not first, resolve_decorator=False) c = [ getattr(escope, 'base_func', None) or escope.base for escope in s if escope.isinstance(er.Function, er.Class) ] if compare in c: # only if we have the correct function we execute # it, otherwise just ignore it. evaluator.follow_path(iter(last), s, scope) return listener.param_possibilities result = [] for params in get_posibilities(evaluator, module, func_name): for p in params: if str(p) == param_name: result += evaluator.eval_statement(p.parent) return result func = param.get_parent_until(pr.Function) current_module = param.get_parent_until() func_name = str(func.name) compare = func if func_name == '__init__' and isinstance(func.parent, pr.Class): func_name = str(func.parent.name) compare = func.parent # get the param name if param.assignment_details: # first assignment details, others would be a syntax error expression_list, op = param.assignment_details[0] else: expression_list = param.expression_list() offset = 1 if expression_list[0] in ['*', '**'] else 0 param_name = str(expression_list[offset].name) # add the listener listener = ParamListener() func.listeners.add(listener) result = [] # This is like backtracking: Get the first possible result. for mod in imports.get_modules_containing_name([current_module], func_name): result = get_params_for_module(mod) if result: break # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) return result
def search_function_call(evaluator, func): """ Returns a list of param names. """ from jedi.evaluate import representation as er def get_params_for_module(module): """ 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: names = module.used_names[func_name] except KeyError: return [] for name in names: parent = name.parent if tree.is_node(parent, 'trailer'): parent = parent.parent trailer = None if tree.is_node(parent, 'power'): for t in parent.children[1:]: if t == '**': break if t.start_pos > name.start_pos and t.children[0] == '(': trailer = t break if trailer is not None: types = evaluator.goto_definition(name) # 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() func_name = unicode(func.name) compare = func if func_name == '__init__': cls = func.get_parent_scope() if isinstance(cls, tree.Class): func_name = unicode(cls.name) compare = cls # add the listener listener = ParamListener() func.listeners.add(listener) try: result = [] # This is like backtracking: Get the first possible result. for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name): result = get_params_for_module(mod) if result: break finally: # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) return result
def usages(evaluator, definitions, search_name, mods): def compare_array(definitions): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ result = [] for d in definitions: module = d.get_parent_until() result.append((module, d.start_pos)) return result def check_call_for_usage(call): stmt = call.parent while not isinstance(stmt.parent, pr.IsScope): stmt = stmt.parent # New definition, call cannot be a part of stmt if len(call.name) == 1 and call.execution is None \ and call.name in stmt.get_defined_names(): # Class params are not definitions (like function params). They # are super classes, that need to be resolved. if not (isinstance(stmt, pr.Param) and isinstance(stmt.parent, pr.Class)): return follow = [] # There might be multiple search_name's in one call_path call_path = list(call.generate_call_path()) for i, name in enumerate(call_path): # name is `pr.NamePart`. if u(name) == search_name: follow.append(call_path[:i + 1]) for call_path in follow: follow_res, search = evaluator.goto(call.parent, call_path) # names can change (getattr stuff), therefore filter names that # don't match `search`. # TODO add something like that in the future - for now usages are # completely broken anyway. #follow_res = [r for r in follow_res if str(r) == search] #print search.start_pos,search_name.start_pos #print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res] follow_res = usages_add_import_modules(evaluator, follow_res, search) compare_follow_res = compare_array(follow_res) # compare to see if they match if any(r in compare_definitions for r in compare_follow_res): yield classes.Definition(evaluator, search) if not definitions: return set() compare_definitions = compare_array(definitions) mods |= set([d.get_parent_until() for d in definitions]) names = [] for m in imports.get_modules_containing_name(mods, search_name): try: stmts = m.used_names[search_name] except KeyError: continue for stmt in stmts: if isinstance(stmt, pr.Import): count = 0 imps = [] for i in stmt.get_all_import_names(): for name_part in i.names: count += 1 if unicode(name_part) == search_name: imps.append((count, name_part)) for used_count, name_part in imps: i = imports.ImportWrapper(evaluator, stmt, kill_count=count - used_count, nested_resolve=True) f = i.follow(is_goto=True) if set(f) & set(definitions): names.append(classes.Definition(evaluator, name_part)) else: for call in helpers.scan_statement_for_calls( stmt, search_name, assignment_details=True): names += check_call_for_usage(call) return names
def search_function_call(evaluator, func): """ Returns a list of param names. """ from jedi.evaluate import representation as er def get_params_for_module(module): """ 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: names = module.used_names[func_name] except KeyError: return [] for name in names: parent = name.parent if pr.is_node(parent, 'trailer'): parent = parent.parent trailer = None if pr.is_node(parent, 'power'): for t in parent.children[1:]: if t == '**': break if t.start_pos > name.start_pos and t.children[ 0] == '(': trailer = t break if trailer is not None: types = evaluator.goto_definition(name) # 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 er.wrap(evaluator, 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() func_name = unicode(func.name) compare = func if func_name == '__init__': cls = func.get_parent_scope() if isinstance(cls, pr.Class): func_name = unicode(cls.name) compare = cls # add the listener listener = ParamListener() func.listeners.add(listener) try: result = [] # This is like backtracking: Get the first possible result. for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name): result = get_params_for_module(mod) if result: break finally: # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) return result
def search_params(evaluator, param): """ This is a dynamic search for params. If you try to complete a type: >>> def func(foo): ... foo >>> func(1) >>> func("") It is not known what the type is, because it cannot be guessed with recursive madness. Therefore one has to analyse the statements that are calling the function, as well as analyzing the incoming params. """ if not settings.dynamic_params: return [] def get_params_for_module(module): """ 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: possible_stmts = module.used_names[func_name] except KeyError: return [] for stmt in possible_stmts: if isinstance(stmt, pr.Import): continue calls = helpers.scan_statement_for_calls(stmt, func_name) for c in calls: # no execution means that params cannot be set call_path = list(c.generate_call_path()) pos = c.start_pos scope = stmt.parent # this whole stuff is just to not execute certain parts # (speed improvement), basically we could just call # ``eval_call_path`` on the call_path and it would # also work. def listRightIndex(lst, value): return len(lst) - lst[-1::-1].index(value) - 1 # Need to take right index, because there could be a # func usage before. call_path_simple = [unicode(d) if isinstance(d, pr.NamePart) else d for d in call_path] i = listRightIndex(call_path_simple, func_name) first, last = call_path[:i], call_path[i + 1:] if not last and not call_path_simple.index(func_name) != i: continue scopes = [scope] if first: scopes = evaluator.eval_call_path(iter(first), scope, pos) pos = None from jedi.evaluate import representation as er for scope in scopes: s = evaluator.find_types(scope, func_name, position=pos, search_global=not first, resolve_decorator=False) c = [getattr(escope, 'base_func', None) or escope.base for escope in s if escope.isinstance(er.Function, er.Class)] if compare in c: # only if we have the correct function we execute # it, otherwise just ignore it. evaluator.follow_path(iter(last), s, scope) return listener.param_possibilities result = [] for params in get_posibilities(evaluator, module, func_name): for p in params: if str(p) == param_name: result += evaluator.eval_statement(p.parent) return result func = param.get_parent_until(pr.Function) current_module = param.get_parent_until() func_name = unicode(func.name) compare = func if func_name == '__init__' and isinstance(func.parent, pr.Class): func_name = unicode(func.parent.name) compare = func.parent # get the param name if param.assignment_details: # first assignment details, others would be a syntax error expression_list, op = param.assignment_details[0] else: expression_list = param.expression_list() offset = 1 if expression_list[0] in ['*', '**'] else 0 param_name = str(expression_list[offset].name) # add the listener listener = ParamListener() func.listeners.add(listener) result = [] # This is like backtracking: Get the first possible result. for mod in imports.get_modules_containing_name([current_module], func_name): result = get_params_for_module(mod) if result: break # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) return result
def search_function_call(evaluator, func): """ Returns a list of param names. """ from jedi.evaluate import representation as er def get_possible_nodes(module, func_name): try: names = module.used_names[func_name] except KeyError: return for name in names: bracket = name.get_next_leaf() trailer = bracket.parent if trailer.type == "trailer" and bracket == "(": yield name, trailer def undecorate(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. if typ.isinstance(er.Function, er.Instance) and typ.decorates is not None: return typ.decorates elif isinstance(typ, er.InstanceElement): return typ.var else: return typ current_module = func.get_parent_until() func_name = unicode(func.name) compare = func if func_name == "__init__": cls = func.get_parent_scope() if isinstance(cls, tree.Class): func_name = unicode(cls.name) compare = cls # add the listener listener = ParamListener() func.listeners.add(listener) try: result = [] i = 0 for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name): for name, trailer in get_possible_nodes(mod, func_name): i += 1 # This is a simple way to stop Jedi's dynamic param recursion # from going wild: The deeper Jedi's in the recursin, the less # code should be evaluated. if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES: return listener.param_possibilities 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: return result finally: # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) return set()
def usages(evaluator, definitions, search_name, mods): def compare_array(definitions): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ result = [] for d in definitions: module = d.get_parent_until() result.append((module, d.start_pos)) return result def check_call_for_usage(call): stmt = call.parent while not isinstance(stmt.parent, pr.IsScope): stmt = stmt.parent # New definition, call cannot be a part of stmt if len(call.name) == 1 and call.execution is None \ and call.name in stmt.get_defined_names(): # Class params are not definitions (like function params). They # are super classes, that need to be resolved. if not (isinstance(stmt, pr.Param) and isinstance(stmt.parent, pr.Class)): return follow = [] # There might be multiple search_name's in one call_path call_path = list(call.generate_call_path()) for i, name in enumerate(call_path): # name is `pr.NamePart`. if u(name) == search_name: follow.append(call_path[:i + 1]) for call_path in follow: follow_res, search = evaluator.goto(call.parent, call_path) # names can change (getattr stuff), therefore filter names that # don't match `search`. # TODO add something like that in the future - for now usages are # completely broken anyway. #follow_res = [r for r in follow_res if str(r) == search] #print search.start_pos,search_name.start_pos #print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res] follow_res = usages_add_import_modules(evaluator, follow_res, search) compare_follow_res = compare_array(follow_res) # compare to see if they match if any(r in compare_definitions for r in compare_follow_res): yield classes.Definition(evaluator, search) if not definitions: return set() compare_definitions = compare_array(definitions) mods |= set([d.get_parent_until() for d in definitions]) names = [] for m in imports.get_modules_containing_name(mods, search_name): try: stmts = m.used_names[search_name] except KeyError: continue for stmt in stmts: if isinstance(stmt, pr.Import): count = 0 imps = [] for i in stmt.get_all_import_names(): for name_part in i.names: count += 1 if unicode(name_part) == search_name: imps.append((count, name_part)) for used_count, name_part in imps: i = imports.ImportWrapper(evaluator, stmt, kill_count=count - used_count, nested_resolve=True) f = i.follow(is_goto=True) if set(f) & set(definitions): names.append(classes.Definition(evaluator, name_part)) else: for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True): names += check_call_for_usage(call) return names