def execute(self, obj, params=(), evaluate_generator=False): if obj.isinstance(er.Function): obj = obj.get_decorated_func() debug.dbg('execute: %s %s', obj, params) try: return stdlib.execute(self, obj, params) except stdlib.NotInStdLib: pass if isinstance(obj, iterable.GeneratorMethod): return obj.execute() elif obj.isinstance(compiled.CompiledObject): if obj.is_executable_class(): return [er.Instance(self, obj, params)] else: return list(obj.execute_function(self, params)) elif obj.isinstance(er.Class): # There maybe executions of executions. return [er.Instance(self, obj, params)] else: stmts = [] if obj.isinstance(er.Function): stmts = er.FunctionExecution(self, obj, params).get_return_types(evaluate_generator) else: if hasattr(obj, 'execute_subscope_by_name'): try: stmts = obj.execute_subscope_by_name('__call__', params) except KeyError: debug.warning("no __call__ func available %s", obj) else: debug.warning("no execution possible %s", obj) debug.dbg('execute result: %s in %s', stmts, obj) return imports.follow_imports(self, stmts)
def execute(self, obj, params=(), evaluate_generator=False): if obj.isinstance(er.Function): obj = obj.get_decorated_func() debug.dbg('execute: %s %s', obj, params) try: return stdlib.execute(self, obj, params) except stdlib.NotInStdLib: pass if isinstance(obj, iterable.GeneratorMethod): return obj.execute() elif obj.isinstance(compiled.CompiledObject): if obj.is_executable_class(): return [er.Instance(self, obj, params)] else: return list(obj.execute_function(self, params)) elif obj.isinstance(er.Class): # There maybe executions of executions. return [er.Instance(self, obj, params)] else: stmts = [] if obj.isinstance(er.Function): stmts = er.FunctionExecution(self, obj, params).get_return_types(evaluate_generator) else: if hasattr(obj, 'execute_subscope_by_name'): try: stmts = obj.execute_subscope_by_name('__call__', params) except KeyError: debug.warning("no __call__ func available %s", obj) else: debug.warning("no execution possible %s", obj) debug.dbg('execute result: %s in %s', stmts, obj) return imports.strip_imports(self, stmts)
def get_iterator_types(inputs): """Returns the types of any iterator (arrays, yields, __iter__, etc).""" iterators = [] # Take the first statement (for has always only # one, remember `in`). And follow it. for it in inputs: if isinstance(it, (er.Generator, er.Array, dynamic.ArrayInstance)): iterators.append(it) else: if not hasattr(it, 'execute_subscope_by_name'): debug.warning('iterator/for loop input wrong', it) continue try: iterators += it.execute_subscope_by_name('__iter__') except KeyError: debug.warning('iterators: No __iter__ method found.') result = [] for gen in iterators: if isinstance(gen, er.Array): # Array is a little bit special, since this is an internal # array, but there's also the list builtin, which is # another thing. result += gen.get_index_types() elif isinstance(gen, er.Instance): # __iter__ returned an instance. name = '__next__' if is_py3k else 'next' try: result += gen.execute_subscope_by_name(name) except KeyError: debug.warning('Instance has no __next__ function', gen) else: # is a generator result += gen.iter_content() return result
def _resolve_descriptors(self, types): """Processes descriptors""" result = [] for r in types: if isinstance(self.scope, (er.Instance, er.Class)) \ and hasattr(r, 'get_descriptor_return'): # handle descriptors with common.ignored(KeyError): result += r.get_descriptor_return(self.scope) continue result.append(r) return result
def descriptor_check(result): """Processes descriptors""" res_new = [] for r in result: if isinstance(scope, (er.Instance, er.Class)) \ and hasattr(r, 'get_descriptor_return'): # handle descriptors with common.ignored(KeyError): res_new += r.get_descriptor_return(scope) continue res_new.append(r) return res_new
def descriptor_check(result): """Processes descriptors""" res_new = [] for r in result: if isinstance(scope, (er.Instance, er.Class)) \ and hasattr(r, 'get_descriptor_return'): # handle descriptors try: res_new += r.get_descriptor_return(scope) continue except KeyError: pass res_new.append(r) return res_new
def _follow_path(self, path, typ, scope): """ Uses a generator and tries to complete the path, e.g.:: foo.bar.baz `_follow_path` is only responsible for completing `.bar.baz`, the rest is done in the `follow_call` function. """ # current is either an Array or a Scope. try: current = next(path) except StopIteration: return None debug.dbg('_follow_path: %s in scope %s', current, typ) result = [] if isinstance(current, pr.Array): # This must be an execution, either () or []. if current.type == pr.Array.LIST: if hasattr(typ, 'get_index_types'): if isinstance(typ, compiled.CompiledObject): # CompiledObject doesn't contain an evaluator instance. result = typ.get_index_types(self, current) else: result = typ.get_index_types(current) elif current.type not in [pr.Array.DICT]: # Scope must be a class or func - make an instance or execution. result = self.execute(typ, current) else: # Curly braces are not allowed, because they make no sense. debug.warning('strange function call with {} %s %s', current, typ) else: # The function must not be decorated with something else. if typ.isinstance(er.Function): typ = typ.get_magic_function_scope() else: # This is the typical lookup while chaining things. if filter_private_variable(typ, scope, current): return [] types = self.find_types(typ, current) result = imports.follow_imports(self, types) return self.follow_path(path, result, scope)
def follow_path(path, scope, call_scope, position=None): """ Uses a generator and tries to complete the path, e.g.:: foo.bar.baz `follow_path` is only responsible for completing `.bar.baz`, the rest is done in the `follow_call` function. """ # current is either an Array or a Scope. try: current = next(path) except StopIteration: return None debug.dbg('follow %s in scope %s' % (current, scope)) result = [] if isinstance(current, pr.Array): # This must be an execution, either () or []. if current.type == pr.Array.LIST: if hasattr(scope, 'get_index_types'): result = scope.get_index_types(current) elif current.type not in [pr.Array.DICT]: # Scope must be a class or func - make an instance or execution. debug.dbg('exe', scope) result = er.Execution(scope, current).get_return_types() else: # Curly braces are not allowed, because they make no sense. debug.warning('strange function call with {}', current, scope) else: # The function must not be decorated with something else. if scope.isinstance(er.Function): scope = scope.get_magic_method_scope() else: # This is the typical lookup while chaining things. if filter_private_variable(scope, call_scope, current): return [] result = imports.strip_imports(find_name(scope, current, position=position)) return follow_paths(path, set(result), call_scope, position=position)
def remove_statements(result): """ This is the part where statements are being stripped. Due to lazy evaluation, statements like a = func; b = a; b() have to be evaluated. """ res_new = [] for r in result: add = [] if r.isinstance(pr.Statement): check_instance = None if isinstance(r, er.InstanceElement) and r.is_class_var: check_instance = r.instance r = r.var # Global variables handling. if r.is_global(): for token_name in r.token_list[1:]: if isinstance(token_name, pr.Name): add = find_name(r.parent, str(token_name)) else: # generated objects are used within executions, but these # objects are in functions, and we have to dynamically # execute first. if isinstance(r, pr.Param): func = r.parent # Instances are typically faked, if the instance is not # called from outside. Here we check it for __init__ # functions and return. if isinstance(func, er.InstanceElement) \ and func.instance.is_generated \ and hasattr(func, 'name') \ and str(func.name) == '__init__' \ and r.position_nr > 0: # 0 would be self r = func.var.params[r.position_nr] # add docstring knowledge doc_params = docstrings.follow_param(r) if doc_params: res_new += doc_params continue if not r.is_generated: res_new += dynamic.search_params(r) if not res_new: c = r.get_commands()[0] if c in ('*', '**'): t = 'tuple' if c == '*' else 'dict' res_new = [er.Instance( find_name(builtin.Builtin.scope, t)[0]) ] if not r.assignment_details: # this means that there are no default params, # so just ignore it. continue # Remove the statement docstr stuff for now, that has to be # implemented with the evaluator class. #if r.docstr: #res_new.append(r) scopes = follow_statement(r, seek_name=name_str) add += remove_statements(scopes) if check_instance is not None: # class renames add = [er.InstanceElement(check_instance, a, True) if isinstance(a, (er.Function, pr.Function)) else a for a in add] res_new += add else: if isinstance(r, pr.Class): r = er.Class(r) elif isinstance(r, pr.Function): r = er.Function(r) if r.isinstance(er.Function) and resolve_decorator: r = r.get_decorated_func() res_new.append(r) debug.dbg('sfn remove, new: %s, old: %s' % (res_new, result)) return res_new
def get_return_types(self, evaluate_generator=False): """ Get the return types of a function. """ stmts = [] if self.base.parent == builtin.Builtin.scope \ and not isinstance(self.base, (Generator, Array)): func_name = str(self.base.name) # some implementations of builtins: if func_name == 'getattr': # follow the first param try: objects = self.follow_var_arg(0) names = self.follow_var_arg(1) except IndexError: debug.warning('getattr() called with to few args.') return [] for obj in objects: if not isinstance(obj, (Instance, Class, pr.Module)): debug.warning('getattr called without instance') continue for arr_name in names: if len(arr_name.var_args) != 1: debug.warning('jedi getattr is too simple') key = arr_name.var_args[0] stmts += evaluate.follow_path(iter([key]), obj, self.base) return stmts elif func_name == 'type': # otherwise it would be a metaclass if len(self.var_args) == 1: objects = self.follow_var_arg(0) return [o.base for o in objects if isinstance(o, Instance)] elif func_name == 'super': # TODO make this able to detect multiple inheritance supers accept = (pr.Function,) func = self.var_args.get_parent_until(accept) if func.isinstance(*accept): cls = func.get_parent_until(accept + (pr.Class,), include_current=False) if isinstance(cls, pr.Class): cls = Class(cls) su = cls.get_super_classes() if su: return [Instance(su[0])] return [] if self.base.isinstance(Class): # There maybe executions of executions. stmts = [Instance(self.base, self.var_args)] elif isinstance(self.base, Generator): return self.base.iter_content() else: # Don't do this with exceptions, as usual, because some deeper # exceptions could be catched - and I wouldn't know what happened. try: self.base.returns except (AttributeError, DecoratorNotFound): if hasattr(self.base, 'execute_subscope_by_name'): try: stmts = self.base.execute_subscope_by_name('__call__', self.var_args) except KeyError: debug.warning("no __call__ func available", self.base) else: debug.warning("no execution possible", self.base) else: stmts = self._get_function_returns(evaluate_generator) debug.dbg('exec result: %s in %s' % (stmts, self)) return imports.strip_imports(stmts)
def remove_statements(result): """ This is the part where statements are being stripped. Due to lazy evaluation, statements like a = func; b = a; b() have to be evaluated. """ res_new = [] for r in result: add = [] if r.isinstance(pr.Statement): check_instance = None if isinstance(r, er.InstanceElement) and r.is_class_var: check_instance = r.instance r = r.var # Global variables handling. if r.is_global(): for token_name in r.token_list[1:]: if isinstance(token_name, pr.Name): add = find_name(r.parent, str(token_name)) else: # generated objects are used within executions, but these # objects are in functions, and we have to dynamically # execute first. if isinstance(r, pr.Param): func = r.parent # Instances are typically faked, if the instance is not # called from outside. Here we check it for __init__ # functions and return. if isinstance(func, er.InstanceElement) \ and func.instance.is_generated \ and hasattr(func, 'name') \ and str(func.name) == '__init__' \ and r.position_nr > 0: # 0 would be self r = func.var.params[r.position_nr] # add docstring knowledge doc_params = docstrings.follow_param(r) if doc_params: res_new += doc_params continue if not r.is_generated: res_new += dynamic.search_params(r) if not r.assignment_details: # this means that there are no default params, # so just ignore it. continue if r.docstr: res_new.append(r) scopes = follow_statement(r, seek_name=name_str) add += remove_statements(scopes) if check_instance is not None: # class renames add = [er.InstanceElement(check_instance, a, True) if isinstance(a, (er.Function, pr.Function)) else a for a in add] res_new += add else: if isinstance(r, pr.Class): r = er.Class(r) elif isinstance(r, pr.Function): r = er.Function(r) if r.isinstance(er.Function): try: r = r.get_decorated_func() except er.DecoratorNotFound: continue res_new.append(r) debug.dbg('sfn remove, new: %s, old: %s' % (res_new, result)) return res_new
def get_return_types(self, evaluate_generator=False): """ Get the return types of a function. """ stmts = [] if self.base.parent == builtin.Builtin.scope \ and not isinstance(self.base, (Generator, Array)): func_name = str(self.base.name) # some implementations of builtins: if func_name == 'getattr': # follow the first param try: objects = self.follow_var_arg(0) names = self.follow_var_arg(1) except IndexError: debug.warning('getattr() called with to few args.') return [] for obj in objects: if not isinstance(obj, (Instance, Class, pr.Module)): debug.warning('getattr called without instance') continue for arr_name in names: if len(arr_name.var_args) != 1: debug.warning('jedi getattr is too simple') key = arr_name.var_args[0] stmts += evaluate.follow_path(iter([key]), obj, self.base) return stmts elif func_name == 'type': # otherwise it would be a metaclass if len(self.var_args) == 1: objects = self.follow_var_arg(0) return [o.base for o in objects if isinstance(o, Instance)] elif func_name == 'super': # TODO make this able to detect multiple inheritance supers accept = (pr.Function, ) func = self.var_args.get_parent_until(accept) if func.isinstance(*accept): cls = func.get_parent_until(accept + (pr.Class, ), include_current=False) if isinstance(cls, pr.Class): cls = Class(cls) su = cls.get_super_classes() if su: return [Instance(su[0])] return [] if self.base.isinstance(Class): # There maybe executions of executions. stmts = [Instance(self.base, self.var_args)] elif isinstance(self.base, Generator): return self.base.iter_content() else: # Don't do this with exceptions, as usual, because some deeper # exceptions could be catched - and I wouldn't know what happened. try: self.base.returns except (AttributeError, DecoratorNotFound): if hasattr(self.base, 'execute_subscope_by_name'): try: stmts = self.base.execute_subscope_by_name( '__call__', self.var_args) except KeyError: debug.warning("no __call__ func available", self.base) else: debug.warning("no execution possible", self.base) else: stmts = self._get_function_returns(evaluate_generator) debug.dbg('exec result: %s in %s' % (stmts, self)) return imports.strip_imports(stmts)