def get_definition(self): """ Returns the definitions of a the path under the cursor. This is not a goto function! This follows complicated paths and returns the end, not the first definition. :return: list of Definition objects, which are basically scopes. :rtype: list """ 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 goto_path = self.module.get_path_under_cursor() context = self.module.get_context() if next(context) in ('class', 'def'): scopes = set([self.module.parser.user_scope]) elif not goto_path: op = self.module.get_operator_under_cursor() scopes = set([keywords.get_operator(op, self.pos)] if op else []) else: scopes = set(self._prepare_goto(goto_path)) scopes = resolve_import_paths(scopes) # add keywords scopes |= keywords.get_keywords(string=goto_path, pos=self.pos) d = set([Definition(s) for s in scopes]) return sorted(d, key=lambda x: (x.module_path, x.start_pos))
def _goto(self, add_import_name=False): """ Used for goto and related_names. """ goto_path = self.module.get_path_under_cursor() context = self.module.get_context() if next(context) in ('class', 'def'): user_scope = self.parser.user_scope definitions = set([user_scope.name]) search_name = str(user_scope.name) elif isinstance(self.parser.user_stmt, parsing.Import): s, name_part = self._get_on_import_stmt() try: definitions = [s.follow(is_goto=True)[0]] except IndexError: definitions = [] search_name = str(name_part) if add_import_name: import_name = self.parser.user_stmt.get_defined_names() # imports have only one name if name_part == import_name[0].names[-1]: definitions.append(import_name[0]) else: stmt = self._get_under_cursor_stmt(goto_path) definitions, search_name = evaluate.goto(stmt) return definitions, search_name
def _goto(self, add_import_name=False): """ Used for goto and related_names. :param add_import_name: TODO add description """ def follow_inexistent_imports(defs): """ Imports can be generated, e.g. following `multiprocessing.dummy` generates an import dummy in the multiprocessing module. The Import doesn't exist -> follow. """ definitions = set(defs) for d in defs: if isinstance(d.parent, parsing.Import) \ and d.start_pos == (0, 0): i = imports.ImportPath(d.parent).follow(is_goto=True) definitions.remove(d) definitions |= follow_inexistent_imports(i) return definitions goto_path = self._module.get_path_under_cursor() context = self._module.get_context() user_stmt = self._parser.user_stmt if next(context) in ('class', 'def'): user_scope = self._parser.user_scope definitions = set([user_scope.name]) search_name = unicode(user_scope.name) elif isinstance(user_stmt, parsing.Import): s, name_part = self._get_on_import_stmt() try: definitions = [s.follow(is_goto=True)[0]] except IndexError: definitions = [] search_name = unicode(name_part) if add_import_name: import_name = user_stmt.get_defined_names() # imports have only one name if name_part == import_name[0].names[-1]: definitions.append(import_name[0]) else: stmt = self._get_under_cursor_stmt(goto_path) defs, search_name = evaluate.goto(stmt) definitions = follow_inexistent_imports(defs) if isinstance(user_stmt, parsing.Statement): if user_stmt.get_assignment_calls().start_pos > self.pos: # The cursor must be after the start, otherwise the # statement is just an assignee. definitions = [user_stmt] return definitions, search_name
def get_definition(self): """ Returns the definitions of a the path under the cursor. This is not a goto function! This follows complicated paths and returns the end, not the first definition. The big difference of goto and get_definition is that goto 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. :return: list of Definition objects, which are basically scopes. :rtype: list """ 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 goto_path = self.module.get_path_under_cursor() context = self.module.get_context() if next(context) in ('class', 'def'): scopes = set([self.module.parser.user_scope]) elif not goto_path: op = self.module.get_operator_under_cursor() scopes = set([keywords.get_operator(op, self.pos)] if op else []) else: scopes = set(self._prepare_goto(goto_path)) scopes = resolve_import_paths(scopes) # add keywords scopes |= keywords.get_keywords(string=goto_path, pos=self.pos) d = set([ api_classes.Definition(s) for s in scopes if not isinstance(s, imports.ImportPath._GlobalNamespace) ]) return sorted(d, key=lambda x: (x.module_path, x.start_pos))
def get_definition(self): """ Returns the definitions of a the path under the cursor. This is not a goto function! This follows complicated paths and returns the end, not the first definition. The big difference of goto and get_definition is that goto 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. :return: list of Definition objects, which are basically scopes. :rtype: list """ 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 goto_path = self.module.get_path_under_cursor() context = self.module.get_context() if next(context) in ('class', 'def'): scopes = set([self.module.parser.user_scope]) elif not goto_path: op = self.module.get_operator_under_cursor() scopes = set([keywords.get_operator(op, self.pos)] if op else []) else: scopes = set(self._prepare_goto(goto_path)) scopes = resolve_import_paths(scopes) # add keywords scopes |= keywords.get_keywords(string=goto_path, pos=self.pos) d = set([api_classes.Definition(s) for s in scopes if not isinstance(s, imports.ImportPath._GlobalNamespace)]) return sorted(d, key=lambda x: (x.module_path, x.start_pos))
def __next__(self): if self.closed: raise MultiLevelStopIteration() try: self.current = next(self.gen) except tokenize.TokenError: # We just ignore this error, I try to handle it earlier - as # good as possible debug.warning('parentheses not closed error') return self.__next__() except IndentationError: # This is an error, that tokenize may produce, because the code # is not indented as it should. Here it just ignores this line # and restarts the parser. # (This is a rather unlikely error message, for normal code, # tokenize seems to be pretty tolerant) debug.warning('indentation error on line %s, ignoring it' % self.current[2][0]) # add the starting line of the last position self.line_offset += self.current[2][0] self.gen = PushBackIterator(tokenize.generate_tokens( self.readline)) return self.__next__() c = list(self.current) # stop if a new class or definition is started at position zero. breaks = ['def', 'class', '@'] if self.stop_on_scope and c[1] in breaks and c[2][1] == 0: if self.first_scope: self.closed = True raise MultiLevelStopIteration() elif c[1] != '@': self.first_scope = True c[2] = self.line_offset + c[2][0], c[2][1] c[3] = self.line_offset + c[3][0], c[3][1] return c
def __next__(self): if self.pushes: return self.pushes.pop() else: return next(self.iterator)