def goto_assignments(self, follow_imports=False): """ Return the first definition found, while optionally following imports. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def filter_follow_imports(names, check): for name in names: if check(name): for result in filter_follow_imports(name.goto(), check): yield result else: yield name names = self._goto() if follow_imports: def check(name): if isinstance(name, er.ModuleName): return False return name.api_type == 'module' else: def check(name): return isinstance(name, imports.SubModuleName) names = filter_follow_imports(names, check) defs = [classes.Definition(self._evaluator, d) for d in set(names)] return helpers.sorted_definitions(defs)
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: user_stmt = self._parser.user_stmt() definitions = self._goto(add_import_name=True) if not definitions: # Without a definition for a name we cannot find references. return [] if not isinstance(user_stmt, pr.Import): # import case is looked at with add_import_name option definitions = usages.usages_add_import_modules( self._evaluator, definitions) module = set([d.get_parent_until() for d in definitions]) module.add(self._parser.module()) names = usages.usages(self._evaluator, definitions, module) for d in set(definitions): names.append(classes.Definition(self._evaluator, d)) finally: settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(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: user_stmt = self._parser.user_stmt() definitions = self._goto(add_import_name=True) if not definitions: # Without a definition for a name we cannot find references. return [] if not isinstance(user_stmt, pr.Import): # import case is looked at with add_import_name option definitions = usages.usages_add_import_modules(self._evaluator, definitions) module = set([d.get_parent_until() for d in definitions]) module.add(self._parser.module()) names = usages.usages(self._evaluator, definitions, module) for d in set(definitions): names.append(classes.Definition(self._evaluator, d)) finally: settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(names))
def _goto(self, line, column, follow_imports=False, follow_builtin_imports=False, only_stubs=False, prefer_stubs=False): tree_name = self._module_node.get_name_of_position((line, column)) if tree_name is None: # Without a name we really just want to jump to the result e.g. # executed by `foo()`, if we the cursor is after `)`. return self.infer(line, column, only_stubs=only_stubs, prefer_stubs=prefer_stubs) name = self._get_module_context().create_name(tree_name) # Make it possible to goto the super class function/attribute # definitions, when they are overwritten. names = [] if name.tree_name.is_definition() and name.parent_context.is_class(): class_node = name.parent_context.tree_node class_value = self._get_module_context().create_value(class_node) mro = class_value.py__mro__() next(mro) # Ignore the first entry, because it's the class itself. for cls in mro: names = cls.goto(tree_name.value) if names: break if not names: names = list(name.goto()) if follow_imports: names = helpers.filter_follow_imports(names) names = convert_names( names, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Definition(self._inference_state, d) for d in set(names)] return helpers.sorted_definitions(defs)
def goto_assignments(self, follow_imports=False): """ Return the first definition found, while optionally following imports. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def filter_follow_imports(names, check): for name in names: if check(name): for result in filter_follow_imports(name.goto(), check): yield result else: yield name tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: return [] context = self._evaluator.create_context(self._get_module(), tree_name) names = list(self._evaluator.goto(context, tree_name)) if follow_imports: def check(name): return name.is_import() else: def check(name): return isinstance(name, imports.SubModuleName) names = filter_follow_imports(names, check) defs = [classes.Definition(self._evaluator, d) for d in set(names)] return helpers.sorted_definitions(defs)
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ leaf = self._get_module().name_for_position(self._pos) if leaf is None: leaf = self._get_module().get_leaf_for_position(self._pos) if leaf is None: return [] definitions = helpers.evaluate_goto_definition(self._evaluator, leaf) names = [s.name for s in definitions] defs = [classes.Definition(self._evaluator, name) for name in names] # The additional set here allows the definitions to become unique in an # API sense. In the internals we want to separate more things than in # the API. return helpers.sorted_definitions(set(defs))
def goto_assignments(self, follow_imports=False): """ Return the first definition found, while optionally following imports. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def filter_follow_imports(names): for name in names: definition = name.get_definition() if definition.type in ('import_name', 'import_from'): imp = imports.ImportWrapper(self._evaluator, name) for name in filter_follow_imports(imp.follow(is_goto=True)): yield name else: yield name names = self._goto() if follow_imports: names = filter_follow_imports(names) defs = [classes.Definition(self._evaluator, d) for d in set(names)] return helpers.sorted_definitions(defs)
def goto(self, line=None, column=None, *, follow_imports=False, follow_builtin_imports=False, only_stubs=False, prefer_stubs=False): """ Goes to the name that defined the object under the cursor. Optionally you can follow imports. Multiple objects may be returned, depending on an if you can have two different versions of a function. :param follow_imports: The method will follow imports. :param follow_builtin_imports: If ``follow_imports`` is True will try to look up names in builtins (i.e. compiled or extension modules). :param only_stubs: Only return stubs for this method. :param prefer_stubs: Prefer stubs to Python objects for this method. :rtype: list of :class:`.Name` """ tree_name = self._module_node.get_name_of_position((line, column)) if tree_name is None: # Without a name we really just want to jump to the result e.g. # executed by `foo()`, if we the cursor is after `)`. return self.infer(line, column, only_stubs=only_stubs, prefer_stubs=prefer_stubs) name = self._get_module_context().create_name(tree_name) # Make it possible to goto the super class function/attribute # definitions, when they are overwritten. names = [] if name.tree_name.is_definition() and name.parent_context.is_class(): class_node = name.parent_context.tree_node class_value = self._get_module_context().create_value(class_node) mro = class_value.py__mro__() next(mro) # Ignore the first entry, because it's the class itself. for cls in mro: names = cls.goto(tree_name.value) if names: break if not names: names = list(name.goto()) if follow_imports: names = helpers.filter_follow_imports(names, follow_builtin_imports) names = convert_names( names, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Name(self._inference_state, d) for d in set(names)] # Avoid duplicates return list(set(helpers.sorted_definitions(defs)))
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_in_module(include_builtins=True): tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: # Must be syntax return [] names = usages.usages_in_module(self._get_module(), tree_name) definitions = [classes.Definition(self._evaluator, n) for n in names] if not include_builtins: definitions = [d for d in definitions if not d.in_builtin_module()] return helpers.sorted_definitions(definitions)
def _references(include_builtins=True): tree_name = self._module_node.get_name_of_position((line, column)) if tree_name is None: # Must be syntax return [] names = find_references(self._get_module_context(), tree_name) definitions = [classes.Definition(self._inference_state, n) for n in names] if not include_builtins: definitions = [d for d in definitions if not d.in_builtin_module()] return helpers.sorted_definitions(definitions)
def _usages(include_builtins=True): tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: # Must be syntax return [] names = usages.usages(self._get_module(), tree_name) definitions = [classes.Definition(self._evaluator, n) for n in names] if not include_builtins: definitions = [d for d in definitions if not d.in_builtin_module()] return helpers.sorted_definitions(definitions)
def goto_assignments(self): """ Return the first definition found. Imports and statements aren't followed. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ results = self._goto() d = [classes.Definition(self._evaluator, d) for d in set(results)] return helpers.sorted_definitions(d)
def _references(include_builtins=True, scope='project'): if scope not in ('project', 'file'): raise ValueError('Only the scopes "file" and "project" are allowed') tree_name = self._module_node.get_name_of_position((line, column)) if tree_name is None: # Must be syntax return [] names = find_references(self._get_module_context(), tree_name, scope == 'file') definitions = [classes.Name(self._inference_state, n) for n in names] if not include_builtins or scope == 'file': definitions = [d for d in definitions if not d.in_builtin_module()] return helpers.sorted_definitions(definitions)
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportPath): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes user_stmt = self._parser.user_stmt_with_whitespace() goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set([self._parser.user_scope()]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: (call, _) = helpers.func_call_and_param_index(user_stmt, self._pos) if call is not None: while call.next is not None: call = call.next # reset cursor position: (row, col) = call.name.end_pos pos = (row, max(col - 1, 0)) self._user_context = UserContext(self.source, pos) # then try to find the path again goto_path = self._user_context.get_path_under_cursor() if not definitions: if goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) d = set([ classes.Definition(self._evaluator, s) for s in definitions if s is not imports.ImportPath.GlobalNamespace ]) return helpers.sorted_definitions(d)
def _goto(self, line, column, follow_imports=False, follow_builtin_imports=False, only_stubs=False, prefer_stubs=False): def filter_follow_imports(names): for name in names: if name.is_import(): new_names = list(filter_follow_imports(name.goto())) found_builtin = False if follow_builtin_imports: for new_name in new_names: if new_name.start_pos is None: found_builtin = True if found_builtin: yield name else: for new_name in new_names: yield new_name else: yield name tree_name = self._module_node.get_name_of_position((line, column)) if tree_name is None: # Without a name we really just want to jump to the result e.g. # executed by `foo()`, if we the cursor is after `)`. return self.infer(line, column, only_stubs=only_stubs, prefer_stubs=prefer_stubs) name = self._get_module_context().create_name(tree_name) names = list(name.goto()) if follow_imports: names = filter_follow_imports(names) names = convert_names( names, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [ classes.Definition(self._inference_state, d) for d in set(names) ] return helpers.sorted_definitions(defs)
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportWrapper): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set( [self._evaluator.wrap(self._parser.user_scope())]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: definitions = set(signature._definition for signature in self.call_signatures()) if re.match('\w[\w\d_]*$', goto_path) and not definitions: user_stmt = self._parser.user_stmt() if user_stmt is not None and user_stmt.type == 'expr_stmt': for name in user_stmt.get_defined_names(): if name.start_pos <= self._pos <= name.end_pos: # TODO scaning for a name and then using it should be # the default. definitions = set( self._evaluator.goto_definition(name)) if not definitions and goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) names = [s.name for s in definitions] defs = [classes.Definition(self._evaluator, name) for name in names] return helpers.sorted_definitions(set(defs))
def infer(self, line=None, column=None, *, only_stubs=False, prefer_stubs=False): """ Return the definitions of under the cursor. It is basically a wrapper around Jedi's type inference. This method follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto` and :meth:`infer` is that :meth:`goto` doesn't follow imports and statements. Multiple objects may be returned, because depending on an option you can have two different versions of a function. :param only_stubs: Only return stubs for this method. :param prefer_stubs: Prefer stubs to Python objects for this method. :rtype: list of :class:`.Name` """ pos = line, column leaf = self._module_node.get_name_of_position(pos) if leaf is None: leaf = self._module_node.get_leaf_for_position(pos) if leaf is None or leaf.type == 'string': return [] if leaf.end_pos == (line, column) and leaf.type == 'operator': next_ = leaf.get_next_leaf() if next_.start_pos == leaf.end_pos \ and next_.type in ('number', 'string', 'keyword'): leaf = next_ context = self._get_module_context().create_context(leaf) values = helpers.infer(self._inference_state, context, leaf) values = convert_values( values, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Name(self._inference_state, c.name) for c in values] # The additional set here allows the definitions to become unique in an # API sense. In the internals we want to separate more things than in # the API. return helpers.sorted_definitions(set(defs))
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportPath): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes user_stmt = self._parser.user_stmt_with_whitespace() goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set([self._parser.user_scope()]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: (call, _) = helpers.func_call_and_param_index(user_stmt, self._pos) if call is not None: while call.next is not None: call = call.next # reset cursor position: (row, col) = call.name.end_pos pos = (row, max(col - 1, 0)) self._user_context = UserContext(self.source, pos) # then try to find the path again goto_path = self._user_context.get_path_under_cursor() if not definitions: if goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) d = set([classes.Definition(self._evaluator, s) for s in definitions if s is not imports.ImportPath.GlobalNamespace]) return helpers.sorted_definitions(d)
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportWrapper): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set([self._evaluator.wrap(self._parser.user_scope())]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: definitions = set(signature._definition for signature in self.call_signatures()) if re.match('\w[\w\d_]*$', goto_path) and not definitions: user_stmt = self._parser.user_stmt() if user_stmt is not None and user_stmt.type == 'expr_stmt': for name in user_stmt.get_defined_names(): if name.start_pos <= self._pos <= name.end_pos: # TODO scaning for a name and then using it should be # the default. definitions = set(self._evaluator.goto_definition(name)) if not definitions and goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) names = [s.name for s in definitions] defs = [classes.Definition(self._evaluator, name) for name in names] return helpers.sorted_definitions(set(defs))
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: user_stmt = self._get_module().get_statement_for_position( self._pos) definitions = self._goto() if not definitions 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 [] definitions = [name] if not definitions: # Without a definition for a name we cannot find references. return [] if not isinstance(user_stmt, tree.Import): # import case is looked at with add_import_name option definitions = usages.usages_add_import_modules( self._evaluator, definitions) module = set([d.get_parent_until() for d in definitions]) module.add(self._get_module()) names = usages.usages(self._evaluator, definitions, module) for d in set(definitions): names.append(classes.Definition(self._evaluator, d)) finally: settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(names))
def goto_assignments(self, follow_imports=False, follow_builtin_imports=False): """ Return the first definition found, while optionally following imports. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :param follow_imports: The goto call will follow imports. :param follow_builtin_imports: If follow_imports is True will decide if it follow builtin imports. :rtype: list of :class:`classes.Definition` """ def filter_follow_imports(names, check): for name in names: if check(name): new_names = list(filter_follow_imports(name.goto(), check)) found_builtin = False if follow_builtin_imports: for new_name in new_names: if new_name.start_pos is None: found_builtin = True if found_builtin: yield name else: for new_name in new_names: yield new_name else: yield name tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: # Without a name we really just want to jump to the result e.g. # executed by `foo()`, if we the cursor is after `)`. return self.goto_definitions() context = self._evaluator.create_context(self._get_module(), tree_name) names = list(self._evaluator.goto(context, tree_name)) if follow_imports: names = filter_follow_imports(names, lambda name: name.is_import()) names = try_stub_to_actual_names(names, prefer_stub_to_compiled=True) defs = [classes.Definition(self._evaluator, d) for d in set(names)] return helpers.sorted_definitions(defs)
def usages(self, additional_module_paths=()): """ Return :class:`classes.Usage` 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.Usage` """ temp, settings.dynamic_flow_information = \ settings.dynamic_flow_information, False user_stmt = self._parser.user_stmt() definitions, search_name = self._goto(add_import_name=True) if isinstance(user_stmt, pr.Statement): c = user_stmt.expression_list()[0] if not isinstance(c, unicode) and self._pos < c.start_pos: # the search_name might be before `=` definitions = [ v for v in user_stmt.get_set_vars() if unicode(v.names[-1]) == search_name ] if not isinstance(user_stmt, pr.Import): # import case is looked at with add_import_name option definitions = usages.usages_add_import_modules( self._evaluator, definitions, search_name) module = set([d.get_parent_until() for d in definitions]) module.add(self._parser.module()) names = usages.usages(self._evaluator, definitions, search_name, module) for d in set(definitions): if isinstance(d, pr.Module): names.append(usages.Usage(self._evaluator, d, d)) elif isinstance(d, er.Instance): # Instances can be ignored, because they have been created by # ``__getattr__``. pass else: names.append(usages.Usage(self._evaluator, d.names[-1], d)) settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(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_assignments(self, follow_imports, follow_builtin_imports, only_stubs=False, prefer_stubs=False): def filter_follow_imports(names, check): for name in names: if check(name): new_names = list(filter_follow_imports(name.goto(), check)) found_builtin = False if follow_builtin_imports: for new_name in new_names: if new_name.start_pos is None: found_builtin = True if found_builtin: yield name else: for new_name in new_names: yield new_name else: yield name tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: # Without a name we really just want to jump to the result e.g. # executed by `foo()`, if we the cursor is after `)`. return self.goto_definitions(only_stubs=only_stubs, prefer_stubs=prefer_stubs) context = self._evaluator.create_context(self._get_module(), tree_name) names = list(self._evaluator.goto(context, tree_name)) if follow_imports: names = filter_follow_imports(names, lambda name: name.is_import()) names = convert_names( names, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Definition(self._evaluator, d) for d in set(names)] return helpers.sorted_definitions(defs)
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` """ tree_name = self._module_node.get_name_of_position(self._pos) if tree_name is None: # Must be syntax return [] names = usages.usages(self._get_module(), tree_name) definitions = [classes.Definition(self._evaluator, n) for n in names] return helpers.sorted_definitions(definitions)
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` """ tree_name = self._get_module_node().get_name_of_position(self._pos) if tree_name is None: # Must be syntax return [] names = usages.usages(self._get_module(), tree_name) definitions = [classes.Definition(self._evaluator, n) for n in names] return helpers.sorted_definitions(definitions)
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportWrapper): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes user_stmt = self._parser.user_stmt_with_whitespace() goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set([er.wrap(self._evaluator, self._parser.user_scope())]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: call, _, _ = search_call_signatures(user_stmt, self._pos) if call is not None: definitions = set(self._evaluator.eval_call(call)) if not definitions: if goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) names = [s.name for s in definitions if s is not imports.ImportWrapper.GlobalNamespace] defs = [classes.Definition(self._evaluator, name) for name in names] return helpers.sorted_definitions(set(defs))
def usages(self, additional_module_paths=()): """ Return :class:`classes.Usage` 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.Usage` """ temp, settings.dynamic_flow_information = \ settings.dynamic_flow_information, False user_stmt = self._parser.user_stmt() definitions, search_name = self._goto(add_import_name=True) if isinstance(user_stmt, pr.Statement): c = user_stmt.expression_list()[0] if not isinstance(c, unicode) and self._pos < c.start_pos: # the search_name might be before `=` definitions = [v for v in user_stmt.get_set_vars() if unicode(v.names[-1]) == search_name] if not isinstance(user_stmt, pr.Import): # import case is looked at with add_import_name option definitions = usages.usages_add_import_modules(self._evaluator, definitions, search_name) module = set([d.get_parent_until() for d in definitions]) module.add(self._parser.module()) names = usages.usages(self._evaluator, definitions, search_name, module) for d in set(definitions): if isinstance(d, pr.Module): names.append(usages.Usage(self._evaluator, d, d)) elif isinstance(d, er.Instance): # Instances can be ignored, because they have been created by # ``__getattr__``. pass else: names.append(usages.Usage(self._evaluator, d.names[-1], d)) settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(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_definitions(self, only_stubs=False, prefer_stubs=False): leaf = self._module_node.get_name_of_position(self._pos) if leaf is None: leaf = self._module_node.get_leaf_for_position(self._pos) if leaf is None: return [] context = self._evaluator.create_context(self._get_module(), leaf) contexts = helpers.evaluate_goto_definition(self._evaluator, context, leaf) contexts = convert_contexts( contexts, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Definition(self._evaluator, c.name) for c in contexts] # The additional set here allows the definitions to become unique in an # API sense. In the internals we want to separate more things than in # the API. return helpers.sorted_definitions(set(defs))
def _infer(self, line, column, only_stubs=False, prefer_stubs=False): pos = line, column leaf = self._module_node.get_name_of_position(pos) if leaf is None: leaf = self._module_node.get_leaf_for_position(pos) if leaf is None or leaf.type == 'string': return [] context = self._get_module_context().create_context(leaf) values = helpers.infer(self._inference_state, context, leaf) values = convert_values( values, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Name(self._inference_state, c.name) for c in values] # The additional set here allows the definitions to become unique in an # API sense. In the internals we want to separate more things than in # the API. return helpers.sorted_definitions(set(defs))
def goto_assignments(self, follow_imports=False): """ Return the first definition found, while optionally following imports. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def filter_follow_imports(names): for name in names: if isinstance(name, (imports.ImportName, TreeNameDefinition)): for context in name.infer(): yield context.name else: yield name names = self._goto() if follow_imports: names = filter_follow_imports(names) defs = [classes.Definition(self._evaluator, d) for d in set(names)] return helpers.sorted_definitions(defs)