def __init__(self, source, line, column, source_path, source_encoding='utf-8'): debug.reset_time() source = modules.source_to_unicode(source, source_encoding) self.pos = line, column self.module = modules.ModuleWithCursor(source_path, source=source, position=self.pos) self.source_path = source_path debug.speed('init')
def __init__(self, source, line, column, source_path, source_encoding='utf-8'): api_classes._clear_caches() debug.reset_time() self.source = modules.source_to_unicode(source, source_encoding) self.pos = line, column self._module = modules.ModuleWithCursor(source_path, source=self.source, position=self.pos) self._source_path = source_path self.source_path = None if source_path is None \ else os.path.abspath(source_path) debug.speed('init')
def __init__(self, source, line, column, source_path, source_encoding='utf-8'): debug.reset_time() try: source = unicode(source, source_encoding, 'replace') # Use 'replace' over 'ignore' to hold code structure. except TypeError: # `source` is already a unicode object pass self.pos = line, column self.module = modules.ModuleWithCursor(source_path, source=source, position=self.pos) self.source_path = source_path debug.speed('init')
def _prepare_goto(self, goto_path, is_like_search=False): """ Base for complete, goto and get_definition. Basically it returns the resolved scopes under cursor. """ debug.dbg('start: %s in %s' % (goto_path, self.parser.user_scope)) user_stmt = self.parser.user_stmt debug.speed('parsed') if not user_stmt and len(goto_path.split('\n')) > 1: # If the user_stmt is not defined and the goto_path is multi line, # something's strange. Most probably the backwards tokenizer # matched to much. return [] if isinstance(user_stmt, parsing.Import): scopes = [self._get_on_import_stmt(is_like_search)[0]] else: # just parse one statement, take it and evaluate it stmt = self._get_under_cursor_stmt(goto_path) scopes = evaluate.follow_statement(stmt) return scopes
def _prepare_goto(self, goto_path, is_like_search=False): """ Base for complete, goto and get_definition. Basically it returns the resolved scopes under cursor. """ debug.dbg('start: %s in %s' % (goto_path, self.parser.scope)) user_stmt = self.parser.user_stmt debug.speed('parsed') if not user_stmt and len(goto_path.split('\n')) > 1: # If the user_stmt is not defined and the goto_path is multi line, # something's strange. Most probably the backwards tokenizer # matched to much. return [] if isinstance(user_stmt, parsing.Import): scopes = [self._get_on_import_stmt(is_like_search)[0]] else: # just parse one statement, take it and evaluate it stmt = self._get_under_cursor_stmt(goto_path) scopes = evaluate.follow_statement(stmt) return scopes
def complete(self): """ An auto completer for python files. :return: list of Completion objects, sorted by name and __ comes last. :rtype: list """ def follow_imports_if_possible(name): # TODO remove this, or move to another place (not used) par = name.parent if isinstance(par, parsing.Import) and not \ isinstance(self.parser.user_stmt, parsing.Import): new = imports.ImportPath(par).follow(is_goto=True) # Only remove the old entry if a new one has been found. #print par, new, par.parent if new: try: return new except AttributeError: # .name undefined pass return [name] debug.speed('complete start') path = self.module.get_path_until_cursor() if re.search('^\.|\.\.$', path): return [] path, dot, like = self._get_completion_parts(path) try: scopes = list(self._prepare_goto(path, True)) except NotFoundError: scopes = [] scope_generator = evaluate.get_names_for_scope( self.parser.user_scope, self.pos) completions = [] for scope, name_list in scope_generator: for c in name_list: completions.append((c, scope)) else: completions = [] debug.dbg('possible scopes', scopes) for s in scopes: if s.isinstance(evaluate.Function): names = s.get_magic_method_names() else: if isinstance(s, imports.ImportPath): if like == 'import': l = self.module.get_line(self.pos[0])[:self.pos[1]] if not l.endswith('import import'): continue names = s.get_defined_names(on_import_stmt=True) else: names = s.get_defined_names() for c in names: completions.append((c, s)) if not dot: # named_params have no dots call_def = self.get_in_function_call() if call_def: if not call_def.module.is_builtin(): for p in call_def.params: completions.append((p.get_name(), p)) # Do the completion if there is no path before and no import stmt. if (not scopes or not isinstance(scopes[0], imports.ImportPath)) \ and not path: # add keywords bs = builtin.Builtin.scope completions += ((k, bs) for k in keywords.get_keywords( all=True)) needs_dot = not dot and path comps = [] for c, s in set(completions): n = c.names[-1] if settings.case_insensitive_completion \ and n.lower().startswith(like.lower()) \ or n.startswith(like): if not evaluate.filter_private_variable(s, self.parser.user_stmt, n): new = api_classes.Completion(c, needs_dot, len(like), s) comps.append(new) debug.speed('complete end') return sorted(comps, key=lambda x: (x.word.startswith('__'), x.word.startswith('_'), x.word.lower()))
def get_in_function_call(self): """ Return the function, that the cursor is in, e.g.: >>> isinstance(| # | <-- cursor is here This would return the `isinstance` function. In contrary: >>> isinstance()| # | <-- cursor is here This would return `None`. """ def check_user_stmt(user_stmt): if user_stmt is None \ or not isinstance(user_stmt, parsing.Statement): return None, 0 ass = helpers.fast_parent_copy(user_stmt.get_assignment_calls()) call, index, stop = helpers.scan_array_for_pos(ass, self.pos) return call, index def check_cache(): """ Do the parsing with a part parser, therefore reduce ressource costs. TODO this is not working with multi-line docstrings, improve. """ if self.source_path is None: return None, 0 try: timestamp, parser = builtin.CachedModule.cache[ self.source_path] except KeyError: return None, 0 part_parser = self.module.get_part_parser() user_stmt = part_parser.user_stmt call, index = check_user_stmt(user_stmt) if call: old_stmt = parser.module.get_statement_for_position(self.pos) if old_stmt is None: return None, 0 old_call, old_index = check_user_stmt(old_stmt) if old_call: # compare repr because that should definitely be the same. # Otherwise the whole thing is out of sync. if repr(old_call) == repr(call): # return the index of the part_parser return old_call, index return None, 0 else: raise NotFoundError() debug.speed('func_call start') try: call, index = check_cache() except NotFoundError: return None debug.speed('func_call parsed') if call is None: # This is a backup, if the above is not successful. user_stmt = self.parser.user_stmt call, index = check_user_stmt(user_stmt) if call is None: return None debug.speed('func_call user_stmt') with common.scale_speed_settings(settings.scale_get_in_function_call): origins = evaluate.follow_call(call) debug.speed('func_call followed') if len(origins) == 0: return None # just take entry zero, because we need just one. executable = origins[0] return api_classes.CallDef(executable, index, call)
def complete(self): """ An auto completer for python files. :return: list of Completion objects, sorted by name and __ comes last. :rtype: list """ def follow_imports_if_possible(name): # TODO remove this, or move to another place (not used) par = name.parent if isinstance(par, parsing.Import) and not \ isinstance(self.parser.user_stmt, parsing.Import): new = imports.ImportPath(par).follow(is_goto=True) # Only remove the old entry if a new one has been found. #print par, new, par.parent if new: try: return new except AttributeError: # .name undefined pass return [name] debug.speed('complete start') path = self.module.get_path_until_cursor() path, dot, like = self._get_completion_parts(path) try: scopes = list(self._prepare_goto(path, True)) except NotFoundError: scopes = [] scope_generator = evaluate.get_names_for_scope( self.parser.user_scope, self.pos) completions = [] for scope, name_list in scope_generator: for c in name_list: completions.append((c, scope)) else: completions = [] debug.dbg('possible scopes', scopes) for s in scopes: if s.isinstance(evaluate.Function): names = s.get_magic_method_names() else: if isinstance(s, imports.ImportPath): if like == 'import': l = self.module.get_line(self.pos[0])[:self.pos[1]] if not l.endswith('import import'): continue names = s.get_defined_names(on_import_stmt=True) else: names = s.get_defined_names() for c in names: completions.append((c, s)) if not dot: # named_params have no dots call_def = self.get_in_function_call() if call_def: if not call_def.module.is_builtin(): for p in call_def.params: completions.append((p.get_name(), p)) # Do the completion if there is no path before and no import stmt. if (not scopes or not isinstance(scopes[0], imports.ImportPath)) \ and not path: # add keywords bs = builtin.Builtin.scope completions += ((k, bs) for k in keywords.get_keywords(all=True)) needs_dot = not dot and path comps = [] for c, s in set(completions): n = c.names[-1] if settings.case_insensitive_completion \ and n.lower().startswith(like.lower()) \ or n.startswith(like): if not evaluate.filter_private_variable( s, self.parser.user_stmt, n): new = api_classes.Completion(c, needs_dot, len(like), s) comps.append(new) debug.speed('complete end') return sorted( comps, key=lambda x: (x.word.startswith('__'), x.word.startswith('_'), x.word.lower()))
def get_in_function_call(self): """ Return the function, that the cursor is in, e.g.: >>> isinstance(| # | <-- cursor is here This would return the `isinstance` function. In contrary: >>> isinstance()| # | <-- cursor is here This would return `None`. """ def check_user_stmt(user_stmt): if user_stmt is None \ or not isinstance(user_stmt, parsing.Statement): return None, 0 ass = helpers.fast_parent_copy(user_stmt.get_assignment_calls()) call, index, stop = helpers.scan_array_for_pos(ass, self.pos) return call, index def check_cache(): """ Do the parsing with a part parser, therefore reduce ressource costs. TODO this is not working with multi-line docstrings, improve. """ if self.source_path is None: return None, 0 try: timestamp, parser = builtin.CachedModule.cache[ self.source_path] except KeyError: return None, 0 part_parser = self.module.get_part_parser() user_stmt = part_parser.user_stmt call, index = check_user_stmt(user_stmt) if call: old_stmt = parser.module.get_statement_for_position(self.pos) if old_stmt is None: return None, 0 old_call, old_index = check_user_stmt(old_stmt) if old_call: # compare repr because that should definitely be the same. # Otherwise the whole thing is out of sync. if repr(old_call) == repr(call): # return the index of the part_parser return old_call, index return None, 0 else: raise NotFoundError() debug.speed('func_call start') try: call, index = check_cache() except NotFoundError: return None debug.speed('func_call parsed') if call is None: # This is a backup, if the above is not successful. user_stmt = self.parser.user_stmt call, index = check_user_stmt(user_stmt) if call is None: return None debug.speed('func_call user_stmt') with helpers.scale_speed_settings(settings.scale_get_in_function_call): origins = evaluate.follow_call(call) debug.speed('func_call followed') if len(origins) == 0: return None # just take entry zero, because we need just one. executable = origins[0] return api_classes.CallDef(executable, index, call)
def get_in_function_call(self): """ Return the function object of the call you're currently in. E.g. if the cursor is here:: >>> abs(# <-- cursor is here This would return the ``abs`` function. On the other hand:: >>> abs()# <-- cursor is here This would return ``None``. :rtype: :class:`api_classes.CallDef` """ def check_user_stmt(user_stmt): if user_stmt is None \ or not isinstance(user_stmt, parsing.Statement): return None, 0 ass = helpers.fast_parent_copy(user_stmt.get_assignment_calls()) call, index, stop = helpers.search_function_call(ass, self.pos) return call, index def check_cache(): """ Do the parsing with a part parser, therefore reduce ressource costs. TODO this is not working with multi-line docstrings, improve. """ if self.source_path is None: return None, 0 try: parser = cache.parser_cache[self.source_path].parser except KeyError: return None, 0 part_parser = self._module.get_part_parser() user_stmt = part_parser.user_stmt call, index = check_user_stmt(user_stmt) if call: old_stmt = parser.module.get_statement_for_position(self.pos) if old_stmt is None: return None, 0 old_call, old_index = check_user_stmt(old_stmt) if old_call: # compare repr because that should definitely be the same. # Otherwise the whole thing is out of sync. if repr(old_call) == repr(call): # return the index of the part_parser return old_call, index return None, 0 else: raise NotFoundError() debug.speed('func_call start') call = None if settings.use_get_in_function_call_cache: try: call, index = check_cache() except NotFoundError: return None user_stmt = self._parser.user_stmt if call is None: # This is a backup, if the above is not successful. call, index = check_user_stmt(user_stmt) if call is None: return None debug.speed('func_call parsed') with common.scale_speed_settings(settings.scale_get_in_function_call): _callable = lambda: evaluate.follow_call(call) origins = cache.cache_get_in_function_call(_callable, user_stmt) debug.speed('func_call followed') if len(origins) == 0: return None # just take entry zero, because we need just one. executable = origins[0] return api_classes.CallDef(executable, index, call)