def iter_content(self): """ The index is here just ignored, because of all the appends, etc. lists/sets are too complicated too handle that. """ items = [] for stmt in self.var_args: for typ in evaluate.follow_statement(stmt): if isinstance(typ, er.Instance) and len(typ.var_args): array = typ.var_args[0] if isinstance(array, ArrayInstance): # prevent recursions # TODO compare Modules if self.var_args.start_pos != array.var_args.start_pos: items += array.iter_content() else: debug.warning("ArrayInstance recursion", self.var_args) continue items += evaluate.get_iterator_types([typ]) # TODO check if exclusion of tuple is a problem here. if isinstance(self.var_args, tuple) or self.var_args.parent is None: return [] # generated var_args should not be checked for arrays module = self.var_args.get_parent_until() is_list = str(self.instance.name) == "list" items += _check_array_additions(self.instance, module, is_list) return items
def get_params_for_module(module): """ Returns the values of a param, or an empty array. """ @search_param_memoize def get_posibilities(module, func_name): try: possible_stmts = module.used_names[func_name] except KeyError: return [] for stmt in possible_stmts: if not isinstance(stmt, parsing.Import): calls = _scan_array(stmt.get_assignment_calls(), func_name) for c in calls: # no execution means that params cannot be set call_path = c.generate_call_path() pos = c.start_pos scope = stmt.parent evaluate.follow_call_path(call_path, scope, pos) return listener.param_possibilities result = [] for params in get_posibilities(module, func_name): for p in params: if str(p) == param_name: result += evaluate.follow_statement(p.parent) return result
def get_params_for_module(module): """ Returns the values of a param, or an empty array. """ @search_param_memoize def get_posibilities(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 = _scan_statement(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 # ``follow_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 = evaluate.follow_call_path(iter(first), scope, pos) pos = None for scope in scopes: s = evaluate.find_name(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. evaluate.follow_paths(iter(last), s, scope) return listener.param_possibilities result = [] for params in get_posibilities(module, func_name): for p in params: if str(p) == param_name: result += evaluate.follow_statement(p.parent) return result
def iter_content(self): """ The index is here just ignored, because of all the appends, etc. lists/sets are too complicated too handle that. """ items = [] for stmt in self.var_args: for typ in evaluate.follow_statement(stmt): if isinstance(typ, er.Instance) and len(typ.var_args): array = typ.var_args[0] if isinstance(array, ArrayInstance): # prevent recursions # TODO compare Modules if self.var_args.start_pos != array.var_args.start_pos: items += array.iter_content() else: debug.warning('ArrayInstance recursion', self.var_args) continue items += evaluate.get_iterator_types([typ]) # TODO check if exclusion of tuple is a problem here. if isinstance(self.var_args, tuple) or self.var_args.parent is None: return [] # generated var_args should not be checked for arrays module = self.var_args.get_parent_until() is_list = str(self.instance.name) == 'list' items += _check_array_additions(self.instance, module, is_list) return items
def follow_var_arg(self, index): try: stmt = self.var_args[index] except IndexError: return [] else: if isinstance(stmt, pr.Statement): return evaluate.follow_statement(stmt) else: return [stmt] # just some arbitrary object
def follow_param(param): func = param.parent_function #print func, param, param.parent_function param_str = search_param_in_docstr(func.docstr, str(param.get_name())) if param_str is not None: p = parsing.PyFuzzyParser(param_str, None, (1, 0), no_docstr=True) p.user_stmt.parent = func return evaluate.follow_statement(p.user_stmt) return []
def check_calls(calls, add_name): """ Calls are processed here. The part before the call is searched and compared with the original Array. """ result = [] for c in calls: call_path = list(c.generate_call_path()) separate_index = call_path.index(add_name) if add_name == call_path[-1] or separate_index == 0: # this means that there is no execution -> [].append # or the keyword is at the start -> append() continue backtrack_path = iter(call_path[:separate_index]) position = c.start_pos scope = c.get_parent_until(pr.IsScope) found = evaluate.follow_call_path(backtrack_path, scope, position) if not compare_array in found: continue params = call_path[separate_index + 1] if not params.values: continue # no params: just ignore it if add_name in ["append", "add"]: for param in params: result += evaluate.follow_statement(param) elif add_name in ["insert"]: try: second_param = params[1] except IndexError: continue else: result += evaluate.follow_statement(second_param) elif add_name in ["extend", "update"]: for param in params: iterators = evaluate.follow_statement(param) result += evaluate.get_iterator_types(iterators) return result
def check_calls(calls, add_name): """ Calls are processed here. The part before the call is searched and compared with the original Array. """ result = [] for c in calls: call_path = list(c.generate_call_path()) separate_index = call_path.index(add_name) if add_name == call_path[-1] or separate_index == 0: # this means that there is no execution -> [].append # or the keyword is at the start -> append() continue backtrack_path = iter(call_path[:separate_index]) position = c.start_pos scope = c.get_parent_until(pr.IsScope) found = evaluate.follow_call_path(backtrack_path, scope, position) if not compare_array in found: continue params = call_path[separate_index + 1] if not params.values: continue # no params: just ignore it if add_name in ['append', 'add']: for param in params: result += evaluate.follow_statement(param) elif add_name in ['insert']: try: second_param = params[1] except IndexError: continue else: result += evaluate.follow_statement(second_param) elif add_name in ['extend', 'update']: for param in params: iterators = evaluate.follow_statement(param) result += evaluate.get_iterator_types(iterators) return result
def _get_function_returns(self, func, evaluate_generator): """ A normal Function execution """ # Feed the listeners, with the params. for listener in func.listeners: listener.execute(self.get_params()) if func.is_generator and not evaluate_generator: return [Generator(func, self.var_args)] else: stmts = docstrings.find_return_types(func) for r in self.returns: if r is not None: stmts += evaluate.follow_statement(r) return stmts
def find_return_types(func): if isinstance(func, evaluate.InstanceElement): func = func.var if isinstance(func, evaluate.Function): func = func.base_func type_str = search_return_in_docstr(func.docstr) if not type_str: return [] p = parsing.PyFuzzyParser(type_str, None, (1, 0), no_docstr=True) p.user_stmt.parent = func return list(evaluate.follow_statement(p.user_stmt))
def get_super_classes(self): supers = [] # TODO care for mro stuff (multiple super classes). for s in self.base.supers: # Super classes are statements. for cls in evaluate.follow_statement(s): if not isinstance(cls, Class): debug.warning('Received non class, as a super class') continue # Just ignore other stuff (user input error). supers.append(cls) if not supers and self.base.parent != builtin.Builtin.scope: # add `object` to classes supers += evaluate.find_name(builtin.Builtin.scope, 'object') return supers
def _prepare_goto(self, goto_path, is_like_search=False): debug.dbg('start: %s in %s' % (goto_path, self.parser.scope)) user_stmt = self.parser.user_stmt 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 follow_param(param): func = param.parent_function # print func, param, param.parent_function param_str = _search_param_in_docstr(func.docstr, str(param.get_name())) user_position = (1, 0) if param_str is not None: # Try to import module part in dotted name. # (e.g., 'threading' in 'threading.Thread'). if "." in param_str: param_str = "import %s\n%s" % (param_str.rsplit(".", 1)[0], param_str) user_position = (2, 0) p = parsing.Parser(param_str, None, user_position, no_docstr=True) if p.user_stmt is None: return [] return evaluate.follow_statement(p.user_stmt) return []
def _prepare_goto(self, goto_path, is_like_search=False): """ Base for complete, goto and 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, pr.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 find_return_types(func): def search_return_in_docstr(code): for p in DOCSTRING_RETURN_PATTERNS: match = p.search(code) if match: return match.group(1) if isinstance(func, er.InstanceElement): func = func.var if isinstance(func, er.Function): func = func.base_func type_str = search_return_in_docstr(func.docstr) if not type_str: return [] p = parsing.Parser(type_str, None, (1, 0), no_docstr=True) p.user_stmt.parent = func return list(evaluate.follow_statement(p.user_stmt))
def follow_definition(self): """ Returns you the original definitions. I strongly recommend not using it for your completions, because it might slow down Jedi. If you want to read only a few objects (<=20). I think it might be useful, especially to get the original docstrings. The basic problem of this function is that it follows all results. This means with 1000 completions (e.g. numpy), it's just PITA slow. """ if self._followed_definitions is None: if self.definition.isinstance(parsing.Statement): defs = evaluate.follow_statement(self.definition) elif self.definition.isinstance(parsing.Import): defs = imports.strip_imports([self.definition]) else: return [self] self._followed_definitions = \ [BaseDefinition(d, d.start_pos) for d in defs] _clear_caches() return self._followed_definitions
def _decorated_func(self, instance=None): """ Returns the function, that is to be executed in the end. This is also the places where the decorators are processed. """ f = self.base_func # Only enter it, if has not already been processed. if not self.is_decorated: for dec in reversed(self.base_func.decorators): debug.dbg('decorator:', dec, f) dec_results = set(evaluate.follow_statement(dec)) if not len(dec_results): debug.warning('decorator not found: %s on %s' % (dec, self.base_func)) return None decorator = dec_results.pop() if dec_results: debug.warning('multiple decorators found', self.base_func, dec_results) # Create param array. old_func = Function(f, is_decorated=True) if instance is not None and decorator.isinstance(Function): old_func = InstanceElement(instance, old_func) instance = None wrappers = Execution(decorator, (old_func,)).get_return_types() if not len(wrappers): debug.warning('no wrappers found', self.base_func) return None if len(wrappers) > 1: debug.warning('multiple wrappers found', self.base_func, wrappers) # This is here, that the wrapper gets executed. f = wrappers[0] debug.dbg('decorator end', f) if f != self.base_func and isinstance(f, pr.Function): f = Function(f) return f
def get_params_for_module(module): """ Returns the values of a param, or an empty array. """ @search_param_memoize def get_posibilities(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 = _scan_statement(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 # ``follow_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 = evaluate.follow_call_path( iter(first), scope, pos) pos = None for scope in scopes: s = evaluate.find_name(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. evaluate.follow_paths(iter(last), s, scope) return listener.param_possibilities result = [] for params in get_posibilities(module, func_name): for p in params: if str(p) == param_name: result += evaluate.follow_statement(p.parent) return result
def _follow_values(self, values): """ helper function for the index getters """ return list(itertools.chain.from_iterable(evaluate.follow_statement(v) for v in values))