def _infer_unaryop( self: nodes.UnaryOp, context: InferenceContext | None = None ) -> Generator[InferenceResult | util.BadUnaryOperationMessage, None, None]: """Infer what an UnaryOp should return when evaluated.""" for operand in self.operand.infer(context): try: yield operand.infer_unary_op(self.op) except TypeError as exc: # The operand doesn't support this operation. yield util.BadUnaryOperationMessage(operand, self.op, exc) except AttributeError as exc: meth = protocols.UNARY_OP_METHOD[self.op] if meth is None: # `not node`. Determine node's boolean # value and negate its result, unless it is # Uninferable, which will be returned as is. bool_value = operand.bool_value() if bool_value is not util.Uninferable: yield nodes.const_factory(not bool_value) else: yield util.Uninferable else: if not isinstance(operand, (bases.Instance, nodes.ClassDef)): # The operation was used on something which # doesn't support it. yield util.BadUnaryOperationMessage(operand, self.op, exc) continue try: try: methods = dunder_lookup.lookup(operand, meth) except AttributeInferenceError: yield util.BadUnaryOperationMessage( operand, self.op, exc) continue meth = methods[0] inferred = next(meth.infer(context=context), None) if inferred is util.Uninferable or not inferred.callable(): continue context = copy_context(context) context.boundnode = operand context.callcontext = CallContext(args=[], callee=inferred) call_results = inferred.infer_call_result(self, context=context) result = next(call_results, None) if result is None: # Failed to infer, return the same type. yield operand else: yield result except AttributeInferenceError as inner_exc: # The unary operation special method was not found. yield util.BadUnaryOperationMessage( operand, self.op, inner_exc) except InferenceError: yield util.Uninferable
def infer_call( self: nodes.Call, context: InferenceContext | None = None, **kwargs: Any) -> Generator[InferenceResult, None, InferenceErrorInfo]: """infer a Call node by trying to guess what the function returns""" callcontext = copy_context(context) callcontext.boundnode = None if context is not None: callcontext.extra_context = _populate_context_lookup( self, context.clone()) for callee in self.func.infer(context): if callee is util.Uninferable: yield callee continue try: if hasattr(callee, "infer_call_result"): callcontext.callcontext = CallContext(args=self.args, keywords=self.keywords, callee=callee) yield from callee.infer_call_result(caller=self, context=callcontext) except InferenceError: continue return InferenceErrorInfo(node=self, context=context)
def from_call(cls, call_node, context: InferenceContext | None = None): """Get a CallSite object from the given Call node. context will be used to force a single inference path. """ # Determine the callcontext from the given `context` object if any. context = context or InferenceContext() callcontext = CallContext(call_node.args, call_node.keywords) return cls(callcontext, context=context)
def _get_binop_contexts(context, left, right): """Get contexts for binary operations. This will return two inference contexts, the first one for x.__op__(y), the other one for y.__rop__(x), where only the arguments are inversed. """ # The order is important, since the first one should be # left.__op__(right). for arg in (right, left): new_context = context.clone() new_context.callcontext = CallContext(args=[arg]) new_context.boundnode = None yield new_context
def getitem(self, index, context=None): new_context = bind_context_to_node(context, self) if not context: context = new_context method = next(self.igetattr("__getitem__", context=context), None) # Create a new CallContext for providing index as an argument. new_context.callcontext = CallContext(args=[index], callee=method) if not isinstance(method, BoundMethod): raise InferenceError("Could not find __getitem__ for {node!r}.", node=self, context=context) if len(method.args.arguments) != 2: # (self, index) raise AstroidTypeError( "__getitem__ for {node!r} does not have correct signature", node=self, context=context, ) return next(method.infer_call_result(self, new_context), None)
def _infer_method_result_truth(instance, method_name, context): # Get the method from the instance and try to infer # its return's truth value. meth = next(instance.igetattr(method_name, context=context), None) if meth and hasattr(meth, "infer_call_result"): if not meth.callable(): return Uninferable try: context.callcontext = CallContext(args=[], callee=meth) for value in meth.infer_call_result(instance, context=context): if value is Uninferable: return value try: inferred = next(value.infer(context=context)) except StopIteration as e: raise InferenceError(context=context) from e return inferred.bool_value() except InferenceError: pass return Uninferable
def class_instance_as_index(node): """Get the value as an index for the given instance. If an instance provides an __index__ method, then it can be used in some scenarios where an integer is expected, for instance when multiplying or subscripting a list. """ context = InferenceContext() try: for inferred in node.igetattr("__index__", context=context): if not isinstance(inferred, bases.BoundMethod): continue context.boundnode = node context.callcontext = CallContext(args=[], callee=inferred) for result in inferred.infer_call_result(node, context=context): if isinstance(result, nodes.Const) and isinstance( result.value, int): return result except InferenceError: pass return None