def _nested(self, comp_fors, parent_context=None): comp_for = comp_fors[0] is_async = 'async' == comp_for.children[comp_for.children.index('for') - 1] input_node = comp_for.children[comp_for.children.index('in') + 1] parent_context = parent_context or self._defining_context input_types = parent_context.eval_node(input_node) # TODO: simulate await if self.is_async cn = ContextualizedNode(parent_context, input_node) iterated = input_types.iterate(cn, is_async=is_async) exprlist = comp_for.children[comp_for.children.index('for') + 1] for i, lazy_context in enumerate(iterated): types = lazy_context.infer() dct = unpack_tuple_to_dict(parent_context, types, exprlist) context_ = self._get_comp_for_context( parent_context, comp_for, ) with predefine_names(context_, comp_for, dct): try: for result in self._nested(comp_fors[1:], context_): yield result except IndexError: iterated = context_.eval_node(self._eval_node()) if self.array_type == 'dict': yield iterated, context_.eval_node(self._eval_node(2)) else: yield iterated
def _nested(self, comp_fors, parent_context=None): evaluator = self.evaluator comp_for = comp_fors[0] input_node = comp_for.children[3] parent_context = parent_context or self._defining_context input_types = parent_context.eval_node(input_node) iterated = py__iter__(evaluator, input_types, input_node) exprlist = comp_for.children[1] for i, lazy_context in enumerate(iterated): types = lazy_context.infer() dct = unpack_tuple_to_dict(evaluator, types, exprlist) context = self._get_comp_for_context( parent_context, comp_for, ) with helpers.predefine_names(context, comp_for, dct): try: for result in self._nested(comp_fors[1:], context): yield result except IndexError: iterated = context.eval_node(self._eval_node()) if self.array_type == 'dict': yield iterated, context.eval_node(self._eval_node(2)) else: yield iterated
def _nested(self, comp_fors, parent_context=None): evaluator = self.evaluator comp_for = comp_fors[0] input_node = comp_for.children[3] parent_context = parent_context or self._defining_context input_types = parent_context.eval_node(input_node) cn = context.ContextualizedNode(parent_context, input_node) iterated = py__iter__(evaluator, input_types, cn) exprlist = comp_for.children[1] for i, lazy_context in enumerate(iterated): types = lazy_context.infer() dct = unpack_tuple_to_dict(parent_context, types, exprlist) context_ = self._get_comp_for_context( parent_context, comp_for, ) with helpers.predefine_names(context_, comp_for, dct): try: for result in self._nested(comp_fors[1:], context_): yield result except IndexError: iterated = context_.eval_node(self._eval_node()) if self.array_type == 'dict': yield iterated, context_.eval_node(self._eval_node(2)) else: yield iterated
def get_yield_lazy_contexts(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.evaluator, 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 LazyKnownContexts(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_context(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_context in ordered: dct = { str(for_stmt.children[1].value): lazy_context.infer() } with helpers.predefine_names(self, for_stmt, dct): for yield_in_same_for_stmt in yields: for result in self._get_yield_lazy_context( yield_in_same_for_stmt): yield result
def _eval_expr_stmt(context, stmt, seek_name=None): """ The starting point of the completion. A statement always owns a call list, which are the calls, that a statement does. In case multiple names are defined in the statement, `seek_name` returns the result for this name. :param stmt: A `tree.ExprStmt`. """ debug.dbg('eval_expr_stmt %s (%s)', stmt, seek_name) rhs = stmt.get_rhs() context_set = context.eval_node(rhs) if seek_name: c_node = ContextualizedName(context, seek_name) context_set = check_tuple_assignments(context.evaluator, c_node, context_set) first_operator = next(stmt.yield_operators(), None) if first_operator not in ('=', None) and first_operator.type == 'operator': # `=` is always the last character in aug assignments -> -1 operator = copy.copy(first_operator) operator.value = operator.value[:-1] name = stmt.get_defined_names()[0].value left = context.py__getattribute__(name, position=stmt.start_pos, search_global=True) for_stmt = tree.search_ancestor(stmt, 'for_stmt') if for_stmt is not None and for_stmt.type == 'for_stmt' and context_set \ and parser_utils.for_stmt_defines_one_name(for_stmt): # Iterate through result and add the values, that's possible # only in for loops without clutter, because they are # predictable. Also only do it, if the variable is not a tuple. node = for_stmt.get_testlist() cn = ContextualizedNode(context, node) ordered = list(cn.infer().iterate(cn)) for lazy_context in ordered: dct = {for_stmt.children[1].value: lazy_context.infer()} with helpers.predefine_names(context, for_stmt, dct): t = context.eval_node(rhs) left = _eval_comparison(context.evaluator, context, left, operator, t) context_set = left else: context_set = _eval_comparison(context.evaluator, context, left, operator, context_set) debug.dbg('eval_expr_stmt result %s', context_set) return context_set
def get_yield_values(self): for_parents = [(y, tree.search_ancestor( y, ('for_stmt', 'funcdef', 'while_stmt', 'if_stmt'))) for y in self.tree_node.yields] # 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 for_stmt.defines_one_name(): # 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 context.get_merged_lazy_context(list(types)) return last_for_stmt = for_stmt evaluator = self.evaluator 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._eval_yield(yield_): yield result else: input_node = for_stmt.get_input_node() for_types = self.eval_node(input_node) ordered = iterable.py__iter__(evaluator, for_types, input_node) ordered = list(ordered) for lazy_context in ordered: dct = {str(for_stmt.children[1]): lazy_context.infer()} with helpers.predefine_names(self, for_stmt, dct): for yield_in_same_for_stmt in yields: for result in self._eval_yield( yield_in_same_for_stmt): yield result
def _eval_stmt(self, context, stmt, seek_name=None): """ The starting point of the completion. A statement always owns a call list, which are the calls, that a statement does. In case multiple names are defined in the statement, `seek_name` returns the result for this name. :param stmt: A `tree.ExprStmt`. """ debug.dbg('eval_statement %s (%s)', stmt, seek_name) rhs = stmt.get_rhs() types = self.eval_element(context, rhs) if seek_name: c_node = ContextualizedName(context, seek_name) types = finder.check_tuple_assignments(self, c_node, types) first_operation = stmt.first_operation() if first_operation not in ( '=', None) and first_operation.type == 'operator': # `=` is always the last character in aug assignments -> -1 operator = copy.copy(first_operation) operator.value = operator.value[:-1] name = str(stmt.get_defined_names()[0]) left = context.py__getattribute__(name, position=stmt.start_pos, search_global=True) for_stmt = tree.search_ancestor(stmt, 'for_stmt') if for_stmt is not None and for_stmt.type == 'for_stmt' and types \ and for_stmt.defines_one_name(): # Iterate through result and add the values, that's possible # only in for loops without clutter, because they are # predictable. Also only do it, if the variable is not a tuple. node = for_stmt.get_input_node() cn = ContextualizedNode(context, node) ordered = list(iterable.py__iter__(self, cn.infer(), cn)) for lazy_context in ordered: dct = {str(for_stmt.children[1]): lazy_context.infer()} with helpers.predefine_names(context, for_stmt, dct): t = self.eval_element(context, rhs) left = precedence.calculate(self, context, left, operator, t) types = left else: types = precedence.calculate(self, context, left, operator, types) debug.dbg('eval_statement result %s', types) return types
def get_yield_lazy_contexts(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.evaluator, 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 LazyKnownContexts(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_context(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_context in ordered: dct = {str(for_stmt.children[1].value): lazy_context.infer()} with helpers.predefine_names(self, for_stmt, dct): for yield_in_same_for_stmt in yields: for result in self._get_yield_lazy_context(yield_in_same_for_stmt): yield result
def get_yield_values(self): for_parents = [(y, tree.search_ancestor(y, ('for_stmt', 'funcdef', 'while_stmt', 'if_stmt'))) for y in self.tree_node.yields] # 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 for_stmt.defines_one_name(): # 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 context.get_merged_lazy_context(list(types)) return last_for_stmt = for_stmt evaluator = self.evaluator 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._eval_yield(yield_): yield result else: input_node = for_stmt.get_input_node() for_types = self.eval_node(input_node) ordered = iterable.py__iter__(evaluator, for_types, input_node) ordered = list(ordered) for lazy_context in ordered: dct = {str(for_stmt.children[1]): lazy_context.infer()} with helpers.predefine_names(self, for_stmt, dct): for yield_in_same_for_stmt in yields: for result in self._eval_yield(yield_in_same_for_stmt): yield result
def _eval_expr_stmt(context, stmt, seek_name=None): """ The starting point of the completion. A statement always owns a call list, which are the calls, that a statement does. In case multiple names are defined in the statement, `seek_name` returns the result for this name. :param stmt: A `tree.ExprStmt`. """ debug.dbg('eval_expr_stmt %s (%s)', stmt, seek_name) rhs = stmt.get_rhs() context_set = context.eval_node(rhs) if seek_name: c_node = ContextualizedName(context, seek_name) context_set = check_tuple_assignments(context.evaluator, c_node, context_set) first_operator = next(stmt.yield_operators(), None) if first_operator not in ('=', None) and first_operator.type == 'operator': # `=` is always the last character in aug assignments -> -1 operator = copy.copy(first_operator) operator.value = operator.value[:-1] name = stmt.get_defined_names()[0].value left = context.py__getattribute__( name, position=stmt.start_pos, search_global=True) for_stmt = tree.search_ancestor(stmt, 'for_stmt') if for_stmt is not None and for_stmt.type == 'for_stmt' and context_set \ and parser_utils.for_stmt_defines_one_name(for_stmt): # Iterate through result and add the values, that's possible # only in for loops without clutter, because they are # predictable. Also only do it, if the variable is not a tuple. node = for_stmt.get_testlist() cn = ContextualizedNode(context, node) ordered = list(cn.infer().iterate(cn)) for lazy_context in ordered: dct = {for_stmt.children[1].value: lazy_context.infer()} with helpers.predefine_names(context, for_stmt, dct): t = context.eval_node(rhs) left = _eval_comparison(context.evaluator, context, left, operator, t) context_set = left else: context_set = _eval_comparison(context.evaluator, context, left, operator, context_set) debug.dbg('eval_expr_stmt result %s', context_set) return context_set
def _eval_stmt(self, context, stmt, seek_name=None): """ The starting point of the completion. A statement always owns a call list, which are the calls, that a statement does. In case multiple names are defined in the statement, `seek_name` returns the result for this name. :param stmt: A `tree.ExprStmt`. """ debug.dbg('eval_statement %s (%s)', stmt, seek_name) rhs = stmt.get_rhs() types = self.eval_element(context, rhs) if seek_name: c_node = ContextualizedName(context, seek_name) types = finder.check_tuple_assignments(self, c_node, types) first_operation = stmt.first_operation() if first_operation not in ('=', None) and first_operation.type == 'operator': # `=` is always the last character in aug assignments -> -1 operator = copy.copy(first_operation) operator.value = operator.value[:-1] name = str(stmt.get_defined_names()[0]) left = context.py__getattribute__( name, position=stmt.start_pos, search_global=True) for_stmt = tree.search_ancestor(stmt, 'for_stmt') if for_stmt is not None and for_stmt.type == 'for_stmt' and types \ and for_stmt.defines_one_name(): # Iterate through result and add the values, that's possible # only in for loops without clutter, because they are # predictable. Also only do it, if the variable is not a tuple. node = for_stmt.get_input_node() cn = ContextualizedNode(context, node) ordered = list(iterable.py__iter__(self, cn.infer(), cn)) for lazy_context in ordered: dct = {str(for_stmt.children[1]): lazy_context.infer()} with helpers.predefine_names(context, for_stmt, dct): t = self.eval_element(context, rhs) left = precedence.calculate(self, context, left, operator, t) types = left else: types = precedence.calculate(self, context, left, operator, types) debug.dbg('eval_statement result %s', types) return types
def eval_element(self, context, element): if not self.infer_enabled: return NO_CONTEXTS if isinstance(context, CompForContext): return eval_node(context, element) if_stmt = element while if_stmt is not None: if_stmt = if_stmt.parent if if_stmt.type in ('if_stmt', 'for_stmt'): break if parser_utils.is_scope(if_stmt): if_stmt = None break predefined_if_name_dict = context.predefined_names.get(if_stmt) # TODO there's a lot of issues with this one. We actually should do # this in a different way. Caching should only be active in certain # cases and this all sucks. if predefined_if_name_dict is None and if_stmt \ and if_stmt.type == 'if_stmt' and self.is_analysis: if_stmt_test = if_stmt.children[1] name_dicts = [{}] # If we already did a check, we don't want to do it again -> If # context.predefined_names is filled, we stop. # We don't want to check the if stmt itself, it's just about # the content. if element.start_pos > if_stmt_test.end_pos: # Now we need to check if the names in the if_stmt match the # names in the suite. if_names = helpers.get_names_of_node(if_stmt_test) element_names = helpers.get_names_of_node(element) str_element_names = [e.value for e in element_names] if any(i.value in str_element_names for i in if_names): for if_name in if_names: definitions = self.goto_definitions(context, if_name) # Every name that has multiple different definitions # causes the complexity to rise. The complexity should # never fall below 1. if len(definitions) > 1: if len(name_dicts) * len(definitions) > 16: debug.dbg('Too many options for if branch evaluation %s.', if_stmt) # There's only a certain amount of branches # Jedi can evaluate, otherwise it will take to # long. name_dicts = [{}] break original_name_dicts = list(name_dicts) name_dicts = [] for definition in definitions: new_name_dicts = list(original_name_dicts) for i, name_dict in enumerate(new_name_dicts): new_name_dicts[i] = name_dict.copy() new_name_dicts[i][if_name.value] = ContextSet([definition]) name_dicts += new_name_dicts else: for name_dict in name_dicts: name_dict[if_name.value] = definitions if len(name_dicts) > 1: result = NO_CONTEXTS for name_dict in name_dicts: with helpers.predefine_names(context, if_stmt, name_dict): result |= eval_node(context, element) return result else: return self._eval_element_if_evaluated(context, element) else: if predefined_if_name_dict: return eval_node(context, element) else: return self._eval_element_if_evaluated(context, element)
def eval_element(self, context, element): if isinstance(context, CompForContext): return eval_node(context, element) if_stmt = element while if_stmt is not None: if_stmt = if_stmt.parent if if_stmt.type in ('if_stmt', 'for_stmt'): break if parser_utils.is_scope(if_stmt): if_stmt = None break predefined_if_name_dict = context.predefined_names.get(if_stmt) # TODO there's a lot of issues with this one. We actually should do # this in a different way. Caching should only be active in certain # cases and this all sucks. if predefined_if_name_dict is None and if_stmt \ and if_stmt.type == 'if_stmt' and self.is_analysis: if_stmt_test = if_stmt.children[1] name_dicts = [{}] # If we already did a check, we don't want to do it again -> If # context.predefined_names is filled, we stop. # We don't want to check the if stmt itself, it's just about # the content. if element.start_pos > if_stmt_test.end_pos: # Now we need to check if the names in the if_stmt match the # names in the suite. if_names = helpers.get_names_of_node(if_stmt_test) element_names = helpers.get_names_of_node(element) str_element_names = [e.value for e in element_names] if any(i.value in str_element_names for i in if_names): for if_name in if_names: definitions = self.goto_definitions(context, if_name) # Every name that has multiple different definitions # causes the complexity to rise. The complexity should # never fall below 1. if len(definitions) > 1: if len(name_dicts) * len(definitions) > 16: debug.dbg('Too many options for if branch evaluation %s.', if_stmt) # There's only a certain amount of branches # Jedi can evaluate, otherwise it will take to # long. name_dicts = [{}] break original_name_dicts = list(name_dicts) name_dicts = [] for definition in definitions: new_name_dicts = list(original_name_dicts) for i, name_dict in enumerate(new_name_dicts): new_name_dicts[i] = name_dict.copy() new_name_dicts[i][if_name.value] = ContextSet(definition) name_dicts += new_name_dicts else: for name_dict in name_dicts: name_dict[if_name.value] = definitions if len(name_dicts) > 1: result = ContextSet() for name_dict in name_dicts: with helpers.predefine_names(context, if_stmt, name_dict): result |= eval_node(context, element) return result else: return self._eval_element_if_evaluated(context, element) else: if predefined_if_name_dict: return eval_node(context, element) else: return self._eval_element_if_evaluated(context, element)