def names(source=None, path=None, encoding='utf-8', all_scopes=False, definitions=True, references=False, environment=None): """ Returns a list of `Definition` objects, containing name parts. This means you can call ``Definition.goto_assignments()`` and get the reference of a name. The parameters are the same as in :py:class:`Script`, except or the following ones: :param all_scopes: If True lists the names of all scopes instead of only the module namespace. :param definitions: If True lists the names that have been defined by a class, function or a statement (``a = b`` returns ``a``). :param references: If True lists all the names that are not listed by ``definitions=True``. E.g. ``a = b`` returns ``b``. """ def def_ref_filter(_def): is_def = _def._name.tree_name.is_definition() return definitions and is_def or references and not is_def # Set line/column to a random position, because they don't matter. script = Script(source, line=1, column=0, path=path, encoding=encoding, environment=environment) module_context = script._get_module() defs = [ classes.Definition( script._evaluator, TreeNameDefinition( module_context.create_context(name if name.parent.type == 'file_input' else name.parent), name ) ) for name in get_module_names(script._module_node, all_scopes) ] return sorted(filter(def_ref_filter, defs), key=lambda x: (x.line, x.column))
def usages_with_additional_modules( script: jedi.api.Script, additional_module_contexts: Tuple[ModuleContext] = ()): """ Based on `jedi.api.Script.usages`, except `additional_modules` are also searched Forked from `jedi.api.Script.usages` on 2017-02-02. Return :class:`classes.Definition` objects, which contain all names that point to the definition of the name under the cursor. This is very useful for refactoring (renaming), or to show all usages of a variable. .. todo:: Implement additional_module_paths :rtype: list of :class:`classes.Definition` """ from jedi import settings from jedi.api import usages from jedi.api import helpers from . import api_usages as alt_api_usages self = script temp, settings.dynamic_flow_information = \ settings.dynamic_flow_information, False try: module_node = self._get_module_node() user_stmt = module_node.get_statement_for_position(self._pos) definition_names = self._goto() #assert not definition_names if not definition_names and isinstance(user_stmt, tree_Import): # For not defined imports (goto doesn't find something, we take # the name as a definition. This is enough, because every name # points to it. name = user_stmt.name_for_position(self._pos) if name is None: # Must be syntax return [] definition_names = [TreeNameDefinition(self._get_module(), name)] if not definition_names: # Without a definition for a name we cannot find references. return [] definition_names = usages.resolve_potential_imports( self._evaluator, definition_names) modules = set([d.get_root_context() for d in definition_names]) modules.add(self._get_module()) for additional_module_context in additional_module_contexts: modules.add(additional_module_context) definitions = alt_api_usages.usages(self._evaluator, definition_names, modules) finally: settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(definitions))
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(self, additional_module_paths=()): """ Return :class:`classes.Definition` objects, which contain all names that point to the definition of the name under the cursor. This is very useful for refactoring (renaming), or to show all usages of a variable. .. todo:: Implement additional_module_paths :rtype: list of :class:`classes.Definition` """ temp, settings.dynamic_flow_information = \ settings.dynamic_flow_information, False try: module_node = self._get_module_node() user_stmt = get_statement_of_position(module_node, self._pos) definition_names = self._goto() if not definition_names and isinstance(user_stmt, tree.Import): # For not defined imports (goto doesn't find something, we take # the name as a definition. This is enough, because every name # points to it. name = user_stmt.get_name_of_position(self._pos) if name is None: # Must be syntax return [] definition_names = [ TreeNameDefinition(self._get_module(), name) ] if not definition_names: # Without a definition for a name we cannot find references. return [] definition_names = usages.resolve_potential_imports( self._evaluator, definition_names) modules = set([d.get_root_context() for d in definition_names]) modules.add(self._get_module()) definitions = usages.usages(self._evaluator, definition_names, modules) finally: settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(definitions))
def goto(self, context, name): definition = name.get_definition(import_name_always=True) if definition is not None: type_ = definition.type if type_ == 'expr_stmt': # Only take the parent, because if it's more complicated than just # a name it's something you can "goto" again. is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: return [TreeNameDefinition(context, name)] elif type_ == 'param': return [ParamName(context, name)] elif type_ in ('funcdef', 'classdef'): return [TreeNameDefinition(context, name)] elif type_ in ('import_from', 'import_name'): module_names = imports.infer_import(context, name, is_goto=True) return module_names par = name.parent node_type = par.type if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': context_set = context.eval_node(trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] if to_evaluate[0] == 'await': to_evaluate.pop(0) context_set = context.eval_node(to_evaluate[0]) for trailer in to_evaluate[1:]: context_set = eval_trailer(context, context_set, trailer) param_names = [] for context in context_set: try: get_param_names = context.get_param_names except AttributeError: pass else: for param_name in get_param_names(): if param_name.string_name == name.value: param_names.append(param_name) return param_names elif node_type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] values = context.eval_node(new_dotted) return unite( value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) if node_type == 'trailer' and par.children[0] == '.': values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True) return unite( value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) else: stmt = tree.search_ancestor( name, 'expr_stmt', 'lambdef' ) or name if stmt.type == 'lambdef': stmt = name return context.py__getattribute__( name, position=stmt.start_pos, search_global=True, is_goto=True )
def _find_names(module_context, tree_name): context = module_context.create_context(tree_name) name = TreeNameDefinition(context, tree_name) found_names = set(name.goto()) found_names.add(name) return _dictionarize(_resolve_names(found_names))
def goto(self, context, name): stmt = name.get_definition() par = name.parent if par.type == 'argument' and par.children[1] == '=' and par.children[ 0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': types = self.eval_element(context, trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_evaluate = trailer.parent.children[:i] types = self.eval_element(context, to_evaluate[0]) for trailer in to_evaluate[1:]: types = self.eval_trailer(context, types, trailer) param_names = [] for typ in types: try: get_param_names = typ.get_param_names except AttributeError: pass else: for param_name in get_param_names(): if param_name.string_name == name.value: param_names.append(param_name) return param_names elif par.type == 'expr_stmt' and name in par.get_defined_names(): # Only take the parent, because if it's more complicated than just # a name it's something you can "goto" again. return [TreeNameDefinition(context, name)] elif par.type == 'param' and par.name: return [ParamName(context, name)] elif isinstance( par, (tree.Param, tree.Function, tree.Class)) and par.name is name: return [TreeNameDefinition(context, name)] elif isinstance(stmt, tree.Import): module_names = imports.infer_import(context, name, is_goto=True) return module_names elif par.type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] values = self.eval_element(context, new_dotted) return unite( value.py__getattribute__( name, name_context=context, is_goto=True) for value in values) if par.type == 'trailer' and par.children[0] == '.': values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True) return unite( value.py__getattribute__( name, name_context=context, is_goto=True) for value in values) else: if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = name return context.py__getattribute__(name, position=stmt.start_pos, search_global=True, is_goto=True)