Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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