def _eval_yield(self, yield_expr): node = yield_expr.children[1] if node.type == 'yield_arg': # It must be a yield from. cn = ContextualizedNode(self, node.children[1]) for lazy_context in iterable.py__iter__(self.evaluator, cn.infer(), cn): yield lazy_context else: yield context.LazyTreeContext(self, node)
def _eval_yield(self, yield_expr): node = yield_expr.children[1] if node.type == 'yield_arg': # It must be a yield from. yield_from_types = self.eval_node(node.children[1]) for lazy_context in iterable.py__iter__(self.evaluator, yield_from_types, node): yield lazy_context else: yield context.LazyTreeContext(self, node)
def _eval_yield(self, yield_expr): element = yield_expr.children[1] if element.type == 'yield_arg': # It must be a yield from. yield_from_types = self._evaluator.eval_element(element.children[1]) for result in iterable.py__iter__(self._evaluator, yield_from_types, element): yield result else: yield self._evaluator.eval_element(element)
def eval_statement(self, 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(rhs) if seek_name: types = finder.check_tuple_assignments(self, types, seek_name) first_operation = stmt.first_operation() if first_operation not in ('=', None) and not isinstance( stmt, er.InstanceElement ) and first_operation.type == 'operator': # TODO don't check for this. id:458 gh:459 # `=` 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]) parent = self.wrap(stmt.get_parent_scope()) left = self.find_types(parent, name, stmt.start_pos, search_global=True) for_stmt = stmt.get_parent_until(tree.ForStmt) if isinstance(for_stmt, tree.ForStmt) 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() for_iterables = self.eval_element(node) ordered = list(iterable.py__iter__(self, for_iterables, node)) for index_types in ordered: dct = {str(for_stmt.children[1]): index_types} self.predefined_if_name_dict_dict[for_stmt] = dct t = self.eval_element(rhs) left = precedence.calculate(self, left, operator, t) types = left if ordered: # If there are no for entries, we cannot iterate and the # types are defined by += entries. Therefore the for loop # is never called. del self.predefined_if_name_dict_dict[for_stmt] else: types = precedence.calculate(self, left, operator, types) debug.dbg('eval_statement result %s', types) return types
def _eval_yield(self, yield_expr): element = yield_expr.children[1] if element.type == 'yield_arg': # It must be a yield from. yield_from_types = self._evaluator.eval_element( element.children[1]) for result in iterable.py__iter__(self._evaluator, yield_from_types, element): yield result else: yield self._evaluator.eval_element(element)
def get_yield_values(self): 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 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_testlist() cn = ContextualizedNode(self, input_node) ordered = iterable.py__iter__(evaluator, cn.infer(), 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._eval_yield( yield_in_same_for_stmt): yield result
def _eval_yield(self, yield_expr): if yield_expr.type == 'keyword': # `yield` just yields None. yield context.LazyKnownContext(compiled.create(self.evaluator, None)) return node = yield_expr.children[1] if node.type == 'yield_arg': # It must be a yield from. cn = ContextualizedNode(self, node.children[1]) for lazy_context in iterable.py__iter__(self.evaluator, cn.infer(), cn): yield lazy_context else: yield context.LazyTreeContext(self, node)
def eval_statement(self, 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(rhs) if seek_name: types = finder.check_tuple_assignments(self, types, seek_name) first_operation = stmt.first_operation() if first_operation not in ("=", None) and not isinstance( stmt, er.InstanceElement ): # TODO don't check for this. # `=` 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]) parent = self.wrap(stmt.get_parent_scope()) left = self.find_types(parent, name, stmt.start_pos, search_global=True) for_stmt = stmt.get_parent_until(tree.ForStmt) if isinstance(for_stmt, tree.ForStmt) 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() for_iterables = self.eval_element(node) ordered = list(iterable.py__iter__(self, for_iterables, node)) for index_types in ordered: dct = {str(for_stmt.children[1]): index_types} self.predefined_if_name_dict_dict[for_stmt] = dct t = self.eval_element(rhs) left = precedence.calculate(self, left, operator, t) types = left if ordered: # If there are no for entries, we cannot iterate and the # types are defined by += entries. Therefore the for loop # is never called. del self.predefined_if_name_dict_dict[for_stmt] else: types = precedence.calculate(self, left, operator, types) debug.dbg("eval_statement result %s", types) return types
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 builtins_reversed(evaluator, sequences, obj, arguments): # While we could do without this variable (just by using sequences), we # want static analysis to work well. Therefore we need to generated the # values again. key, lazy_context = next(arguments.unpack()) ordered = list(iterable.py__iter__(evaluator, sequences, lazy_context.data)) rev = list(reversed(ordered)) # Repack iterator values and then run it the normal way. This is # necessary, because `reversed` is a function and autocompletion # would fail in certain cases like `reversed(x).__iter__` if we # just returned the result directly. seq = iterable.FakeSequence(evaluator, 'list', rev) arguments = param.ValuesArguments([[seq]]) return set([CompiledInstance(evaluator, evaluator.BUILTINS, obj, arguments)])
def _eval_yield(self, yield_expr): if yield_expr.type == 'keyword': # `yield` just yields None. yield context.LazyKnownContext( compiled.create(self.evaluator, None)) return node = yield_expr.children[1] if node.type == 'yield_arg': # It must be a yield from. cn = ContextualizedNode(self, node.children[1]) for lazy_context in iterable.py__iter__(self.evaluator, cn.infer(), cn): yield lazy_context else: yield context.LazyTreeContext(self, node)
def builtins_reversed(evaluator, sequences, obj, arguments): # While we could do without this variable (just by using sequences), we # want static analysis to work well. Therefore we need to generated the # values again. first_arg = next(arguments.as_tuple())[0] ordered = list(iterable.py__iter__(evaluator, sequences, first_arg)) rev = [iterable.AlreadyEvaluated(o) for o in reversed(ordered)] # Repack iterator values and then run it the normal way. This is # necessary, because `reversed` is a function and autocompletion # would fail in certain cases like `reversed(x).__iter__` if we # just returned the result directly. rev = iterable.AlreadyEvaluated( [iterable.FakeSequence(evaluator, rev, 'list')] ) return set([er.Instance(evaluator, obj, param.Arguments(evaluator, [rev]))])
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.iter_yield_exprs()] # 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 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_testlist() cn = ContextualizedNode(self, input_node) ordered = iterable.py__iter__(evaluator, cn.infer(), 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._eval_yield(yield_in_same_for_stmt): yield result
def check_tuple_assignments(evaluator, types, name): """ Checks if tuples are assigned. """ for index, node in name.assignment_indexes(): iterated = iterable.py__iter__(evaluator, types, node) for _ in range(index + 1): try: types = next(iterated) except StopIteration: # We could do this with the default param in next. But this # would allow this loop to run for a very long time if the # index number is high. Therefore break if the loop is # finished. types = set() break return types
def builtins_reversed(evaluator, sequences, obj, arguments): # While we could do without this variable (just by using sequences), we # want static analysis to work well. Therefore we need to generated the # values again. key, lazy_context = next(arguments.unpack()) ordered = list(iterable.py__iter__(evaluator, sequences, lazy_context.data)) rev = list(reversed(ordered)) # Repack iterator values and then run it the normal way. This is # necessary, because `reversed` is a function and autocompletion # would fail in certain cases like `reversed(x).__iter__` if we # just returned the result directly. seq = iterable.FakeSequence(evaluator, 'list', rev) arguments = param.ValuesArguments([[seq]]) return set( [CompiledInstance(evaluator, evaluator.BUILTINS, obj, arguments)])
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_types(self): yields = self.yields stopAt = tree.ForStmt, tree.WhileStmt, FunctionExecution, tree.IfStmt for_parents = [(x, x.get_parent_until((stopAt))) for x in 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 \ 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: yields_order.append((None, [yield_])) else: yield self.get_return_types(check_yields=True) 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 = evaluator.eval_element(input_node) ordered = iterable.py__iter__(evaluator, for_types, input_node) for index_types in ordered: dct = {str(for_stmt.children[1]): index_types} evaluator.predefined_if_name_dict_dict[for_stmt] = dct for yield_in_same_for_stmt in yields: for result in self._eval_yield(yield_in_same_for_stmt): yield result del evaluator.predefined_if_name_dict_dict[for_stmt]
def _paths_from_assignment(module_context, expr_stmt): """ Extracts the assigned strings from an assignment that looks as follows:: >>> sys.path[0:0] = ['module/path', 'another/module/path'] This function is in general pretty tolerant (and therefore 'buggy'). However, it's not a big issue usually to add more paths to Jedi's sys_path, because it will only affect Jedi in very random situations and by adding more paths than necessary, it usually benefits the general user. """ for assignee, operator in zip(expr_stmt.children[::2], expr_stmt.children[1::2]): try: assert operator in ['=', '+='] assert assignee.type in ('power', 'atom_expr') and \ len(assignee.children) > 1 c = assignee.children assert c[0].type == 'name' and c[0].value == 'sys' trailer = c[1] assert trailer.children[0] == '.' and trailer.children[ 1].value == 'path' # TODO Essentially we're not checking details on sys.path # manipulation. Both assigment of the sys.path and changing/adding # parts of the sys.path are the same: They get added to the current # sys.path. """ execution = c[2] assert execution.children[0] == '[' subscript = execution.children[1] assert subscript.type == 'subscript' assert ':' in subscript.children """ except AssertionError: continue from jedi.evaluate.iterable import py__iter__ from jedi.evaluate.precedence import is_string cn = ContextualizedNode(module_context.create_context(expr_stmt), expr_stmt) for lazy_context in py__iter__(module_context.evaluator, cn.infer(), cn): for context in lazy_context.infer(): if is_string(context): yield context.obj
def check_tuple_assignments(evaluator, contextualized_name, types): """ Checks if tuples are assigned. """ lazy_context = None for index, node in contextualized_name.assignment_indexes(): cn = ContextualizedNode(contextualized_name.context, node) iterated = iterable.py__iter__(evaluator, types, cn) for _ in range(index + 1): try: lazy_context = next(iterated) except StopIteration: # We could do this with the default param in next. But this # would allow this loop to run for a very long time if the # index number is high. Therefore break if the loop is # finished. return set() types = lazy_context.infer() return types
def _paths_from_assignment(evaluator, expr_stmt): """ Extracts the assigned strings from an assignment that looks as follows:: >>> sys.path[0:0] = ['module/path', 'another/module/path'] This function is in general pretty tolerant (and therefore 'buggy'). However, it's not a big issue usually to add more paths to Jedi's sys_path, because it will only affect Jedi in very random situations and by adding more paths than necessary, it usually benefits the general user. """ for assignee, operator in zip(expr_stmt.children[::2], expr_stmt.children[1::2]): try: assert operator in ['=', '+='] assert tree.is_node(assignee, 'power', 'atom_expr') and \ len(assignee.children) > 1 c = assignee.children assert c[0].type == 'name' and c[0].value == 'sys' trailer = c[1] assert trailer.children[0] == '.' and trailer.children[1].value == 'path' # TODO Essentially we're not checking details on sys.path # manipulation. Both assigment of the sys.path and changing/adding # parts of the sys.path are the same: They get added to the current # sys.path. """ execution = c[2] assert execution.children[0] == '[' subscript = execution.children[1] assert subscript.type == 'subscript' assert ':' in subscript.children """ except AssertionError: continue from jedi.evaluate.iterable import py__iter__ from jedi.evaluate.precedence import is_string types = evaluator.eval_element(expr_stmt) for types in py__iter__(evaluator, types, expr_stmt): for typ in types: if is_string(typ): yield typ.obj