def get_yield_lazy_values(self, is_async=False): # TODO: if is_async, wrap yield statements in Awaitable/async_generator_asend for_parents = [ (y, tree.search_ancestor(y, 'for_stmt', 'funcdef', 'while_stmt', 'if_stmt')) for y in get_yield_exprs(self.inference_state, self.tree_node) ] # Calculate if the yields are placed within the same for loop. yields_order = [] last_for_stmt = None for yield_, for_stmt in for_parents: # For really simple for loops we can predict the order. Otherwise # we just ignore it. parent = for_stmt.parent if parent.type == 'suite': parent = parent.parent if for_stmt.type == 'for_stmt' and parent == self.tree_node \ and parser_utils.for_stmt_defines_one_name(for_stmt): # Simplicity for now. if for_stmt == last_for_stmt: yields_order[-1][1].append(yield_) else: yields_order.append((for_stmt, [yield_])) elif for_stmt == self.tree_node: yields_order.append((None, [yield_])) else: types = self.get_return_values(check_yields=True) if types: yield LazyKnownValues(types) return last_for_stmt = for_stmt for for_stmt, yields in yields_order: if for_stmt is None: # No for_stmt, just normal yields. for yield_ in yields: for result in self._get_yield_lazy_value(yield_): yield result else: input_node = for_stmt.get_testlist() cn = ContextualizedNode(self, input_node) ordered = cn.infer().iterate(cn) ordered = list(ordered) for lazy_value in ordered: dct = {str(for_stmt.children[1].value): lazy_value.infer()} with self.predefine_names(for_stmt, dct): for yield_in_same_for_stmt in yields: for result in self._get_yield_lazy_value( yield_in_same_for_stmt): yield result
def infer(self): """ Created to be used by inheritance. """ inference_state = self.inference_state is_coroutine = self.tree_node.parent.type in ('async_stmt', 'async_funcdef') is_generator = bool(get_yield_exprs(inference_state, self.tree_node)) from jedi.inference.gradual.typing import GenericClass if is_coroutine: if is_generator: if inference_state.environment.version_info < (3, 6): return NO_VALUES async_generator_classes = inference_state.typing_module \ .py__getattribute__('AsyncGenerator') yield_values = self.merge_yield_values(is_async=True) # The contravariant doesn't seem to be defined. generics = (yield_values.py__class__(), NO_VALUES) return ValueSet( # In Python 3.6 AsyncGenerator is still a class. GenericClass(c, generics) for c in async_generator_classes).execute_annotation() else: if inference_state.environment.version_info < (3, 5): return NO_VALUES async_classes = inference_state.typing_module.py__getattribute__( 'Coroutine') return_values = self.get_return_values() # Only the first generic is relevant. generics = (return_values.py__class__(), NO_VALUES, NO_VALUES) return ValueSet( GenericClass(c, generics) for c in async_classes).execute_annotation() else: if is_generator: return ValueSet([iterable.Generator(inference_state, self)]) else: return self.get_return_values()
def get_return_values(self, check_yields=False): funcdef = self.tree_node if funcdef.type == 'lambdef': return self.infer_node(funcdef.children[-1]) if check_yields: value_set = NO_VALUES returns = get_yield_exprs(self.inference_state, funcdef) else: value_set = self._infer_annotations() if value_set: # If there are annotations, prefer them over anything else. # This will make it faster. return value_set value_set |= docstrings.infer_return_types(self._value) returns = funcdef.iter_return_stmts() for r in returns: check = flow_analysis.reachability_check(self, funcdef, r) if check is flow_analysis.UNREACHABLE: debug.dbg('Return unreachable: %s', r) else: if check_yields: value_set |= ValueSet.from_sets( lazy_value.infer() for lazy_value in self._get_yield_lazy_value(r)) else: try: children = r.children except AttributeError: ctx = compiled.builtin_from_name( self.inference_state, u'None') value_set |= ValueSet([ctx]) else: value_set |= self.infer_node(children[1]) if check is flow_analysis.REACHABLE: debug.dbg('Return reachable: %s', r) break return value_set
def is_generator(self): return bool(get_yield_exprs(self.inference_state, self.tree_node))