示例#1
0
    def bool_value(self):
        """Infer the truth value for an Instance

        The truth value of an instance is determined by these conditions:

           * if it implements __bool__ on Python 3 or __nonzero__
             on Python 2, then its bool value will be determined by
             calling this special method and checking its result.
           * when this method is not defined, __len__() is called, if it
             is defined, and the object is considered true if its result is
             nonzero. If a class defines neither __len__() nor __bool__(),
             all its instances are considered true.
        """
        context = contextmod.InferenceContext()
        context.callcontext = contextmod.CallContext(args=[])
        context.boundnode = self

        try:
            result = _infer_method_result_truth(self, BOOL_SPECIAL_METHOD,
                                                context)
        except (exceptions.InferenceError, exceptions.AttributeInferenceError):
            # Fallback to __len__.
            try:
                result = _infer_method_result_truth(self, '__len__', context)
            except (exceptions.AttributeInferenceError,
                    exceptions.InferenceError):
                return True
        return result
示例#2
0
def query_call(self: nodes.Call, context=None):
    """query a Call node by trying to guess what the function returns"""
    callcontext = contextmod.copy_context(context)
    callcontext.callcontext = contextmod.CallContext(args=self.args,
                                                     keywords=self.keywords)
    callcontext.boundnode = None
    if context is not None:
        # extra context saved the args, what's for?
        callcontext.extra_context = _populate_context_lookup(
            self, context.clone())

    for callee in self.func.query(context):
        if callee is util.Uninferable:
            yield callee
            continue
        if callee is util.Unqueryable:
            if not isinstance(self.keywords, None):
                # not implemented
                print(kv)
                assert False
            return self.args

        try:
            if hasattr(callee, "query_call_result"):
                # no filed sensitive here
                yield from callee.query_call_result(caller=self,
                                                    context=callcontext)
        except exceptions.InferenceError:
            continue
    return dict(node=self, context=context)
示例#3
0
文件: inference.py 项目: tcwz/astroid
def infer_call(self, context=None):
    """infer a Call node by trying to guess what the function returns"""
    callcontext = context.clone()
    callcontext.callcontext = contextmod.CallContext(args=self.args,
                                                     keywords=self.keywords)
    callcontext.boundnode = None
    extra_context = {}
    if context is not None:
        extra_context = _populate_context_lookup(self, context.clone())
        callcontext.extra_context = extra_context
    for callee in self.func.infer(context):
        if callee is util.Uninferable:
            yield callee
            continue
        try:
            if hasattr(callee, 'infer_call_result'):
                yield from callee.infer_call_result(
                    caller=self,
                    context=callcontext,
                )
        except exceptions.InferenceError:
            ## XXX log error ?
            continue
    # Explicit StopIteration to return error information, see comment
    # in raise_if_nothing_inferred.
    return dict(node=self, context=context)
示例#4
0
def instance_getitem(self, index, context=None):
    # Rewrap index to Const for this case
    new_context = contextmod.bind_context_to_node(context, self)
    if not context:
        context = new_context

    # Create a new callcontext for providing index as an argument.
    new_context.callcontext = contextmod.CallContext(args=[index])

    method = next(self.igetattr("__getitem__", context=context), None)
    if not isinstance(method, bases.BoundMethod):
        raise exceptions.InferenceError(
            "Could not find __getitem__ for {node!r}.",
            node=self,
            context=context)

    try:
        return next(method.infer_call_result(self, new_context))
    except StopIteration as exc:
        raise exceptions.InferenceError(
            message="Inference for {node!r}[{index!s}] failed.",
            node=self,
            index=index,
            context=context,
        ) from exc
示例#5
0
def instance_getitem(self, index, context=None):
    # Rewrap index to Const for this case
    if context:
        new_context = context.clone()
    else:
        context = new_context = contextmod.InferenceContext()

    # Create a new callcontext for providing index as an argument.
    new_context.callcontext = contextmod.CallContext(args=[index])
    new_context.boundnode = self

    method = next(self.igetattr('__getitem__', context=context))
    if not isinstance(method, bases.BoundMethod):
        raise exceptions.InferenceError(
            'Could not find __getitem__ for {node!r}.',
            node=self,
            context=context)

    try:
        return next(method.infer_call_result(self, new_context))
    except StopIteration:
        util.reraise(
            exceptions.InferenceError(
                message='Inference for {node!r}[{index!s}] failed.',
                node=self,
                index=index,
                context=context))
示例#6
0
def _infer_unaryop(self, context=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 exceptions.AttributeInferenceError:
                        yield util.BadUnaryOperationMessage(
                            operand, self.op, exc)
                        continue

                    meth = methods[0]
                    inferred = next(meth.infer(context=context))
                    if inferred is util.Uninferable or not inferred.callable():
                        continue

                    context = contextmod.copy_context(context)
                    context.callcontext = contextmod.CallContext(
                        args=[operand])
                    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 exceptions.AttributeInferenceError as exc:
                    # The unary operation special method was not found.
                    yield util.BadUnaryOperationMessage(operand, self.op, exc)
                except exceptions.InferenceError:
                    yield util.Uninferable
示例#7
0
    def from_call(cls, call_node, context=None):
        """Get a CallSite object from the given Call node.

        :param context:
            An instance of :class:`astroid.context.Context` that will be used
            to force a single inference path.
        """

        # Determine the callcontext from the given `context` object if any.
        context = context or contextmod.InferenceContext()
        callcontext = contextmod.CallContext(call_node.args, call_node.keywords)
        return cls(callcontext, context=context)
示例#8
0
def _infer_context_manager(self, mgr, context):
    try:
        inferred = next(mgr.infer(context=context))
    except (StopIteration, exceptions.InferenceError):
        return
    if isinstance(inferred, bases.Generator):
        # Check if it is decorated with contextlib.contextmanager.
        func = inferred.parent
        if not func.decorators:
            return
        for decorator_node in func.decorators.nodes:
            try:
                decorator = next(decorator_node.infer(context))
            except StopIteration:
                return
            if isinstance(decorator, nodes.FunctionDef):
                if decorator.qname() == _CONTEXTLIB_MGR:
                    break
        else:
            # It doesn't interest us.
            return

        # Get the first yield point. If it has multiple yields,
        # then a RuntimeError will be raised.

        possible_yield_points = func.nodes_of_class(nodes.Yield)
        # Ignore yields in nested functions
        yield_point = next(
            (node for node in possible_yield_points if node.scope() == func),
            None)
        if yield_point:
            if not yield_point.value:
                const = nodes.Const(None)
                const.parent = yield_point
                const.lineno = yield_point.lineno
                yield const
            else:
                yield from yield_point.value.infer(context=context)
    elif isinstance(inferred, bases.Instance):
        try:
            enter = next(inferred.igetattr("__enter__", context=context))
        except (
                StopIteration,
                exceptions.InferenceError,
                exceptions.AttributeInferenceError,
        ):
            return
        if not isinstance(enter, bases.BoundMethod):
            return
        if not context.callcontext:
            context.callcontext = contextmod.CallContext(args=[inferred])
        yield from enter.infer_call_result(self, context)
示例#9
0
文件: bases.py 项目: DudeNr33/astroid
 def getitem(self, index, context=None):
     # TODO: Rewrap index to Const for this case
     new_context = contextmod.bind_context_to_node(context, self)
     if not context:
         context = new_context
     # Create a new CallContext for providing index as an argument.
     new_context.callcontext = contextmod.CallContext(args=[index])
     method = next(self.igetattr("__getitem__", context=context), None)
     if not isinstance(method, BoundMethod):
         raise exceptions.InferenceError(
             "Could not find __getitem__ for {node!r}.",
             node=self,
             context=context)
     return next(method.infer_call_result(self, new_context))
示例#10
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 = contextmod.CallContext(args=[arg])
        new_context.boundnode = None
        yield new_context
示例#11
0
def infer_call(self, context=None):
    """infer a Call node by trying to guess what the function returns"""
    callcontext = context.clone()
    callcontext.callcontext = contextmod.CallContext(args=self.args,
                                                     keywords=self.keywords)
    callcontext.boundnode = None
    for callee in self.func.infer(context):
        if callee is util.YES:
            yield callee
            continue
        try:
            if hasattr(callee, 'infer_call_result'):
                for inferred in callee.infer_call_result(self, callcontext):
                    yield inferred
        except exceptions.InferenceError:
            ## XXX log error ?
            continue
示例#12
0
def _infer_context_manager(self, mgr, context):
    try:
        inferred = next(mgr.infer(context=context))
    except exceptions.InferenceError:
        return
    if isinstance(inferred, bases.Generator):
        # Check if it is decorated with contextlib.contextmanager.
        func = inferred.parent
        if not func.decorators:
            return
        for decorator_node in func.decorators.nodes:
            decorator = next(decorator_node.infer(context))
            if isinstance(decorator, nodes.FunctionDef):
                if decorator.qname() == _CONTEXTLIB_MGR:
                    break
        else:
            # It doesn't interest us.
            return

        # Get the first yield point. If it has multiple yields,
        # then a RuntimeError will be raised.
        # TODO(cpopa): Handle flows.
        yield_point = next(func.nodes_of_class(nodes.Yield), None)
        if yield_point:
            if not yield_point.value:
                # TODO(cpopa): an empty yield. Should be wrapped to Const.
                const = nodes.Const(None)
                const.parent = yield_point
                const.lineno = yield_point.lineno
                yield const
            else:
                for inferred in yield_point.value.infer(context=context):
                    yield inferred
    elif isinstance(inferred, bases.Instance):
        try:
            enter = next(inferred.igetattr('__enter__', context=context))
        except (exceptions.InferenceError, exceptions.AttributeInferenceError):
            return
        if not isinstance(enter, bases.BoundMethod):
            return
        if not context.callcontext:
            context.callcontext = contextmod.CallContext(args=[inferred])
        for result in enter.infer_call_result(self, context):
            yield result
示例#13
0
 def getitem(self, index, context=None):
     # TODO: Rewrap index to Const for this case
     new_context = contextmod.bind_context_to_node(context, self)
     if not context:
         context = new_context
     # Create a new CallContext for providing index as an argument.
     new_context.callcontext = contextmod.CallContext(args=[index])
     method = next(self.igetattr("__getitem__", context=context), None)
     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)
示例#14
0
def infer_call(self, context=None):
    """infer a Call node by trying to guess what the function returns"""
    callcontext = contextmod.copy_context(context)
    callcontext.callcontext = contextmod.CallContext(
        args=self.args, keywords=self.keywords
    )
    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"):
                yield from callee.infer_call_result(caller=self, context=callcontext)
        except exceptions.InferenceError:
            continue
    return dict(node=self, context=context)
示例#15
0
def instance_getitem(self, index, context=None):
    # Rewrap index to Const for this case
    index = nodes.Const(index)
    if context:
        new_context = context.clone()
    else:
        context = new_context = contextmod.InferenceContext()

    # Create a new callcontext for providing index as an argument.
    new_context.callcontext = contextmod.CallContext(args=[index])
    new_context.boundnode = self

    method = next(self.igetattr('__getitem__', context=context))
    if not isinstance(method, bases.BoundMethod):
        raise exceptions.InferenceError

    try:
        return next(method.infer_call_result(self, new_context))
    except StopIteration:
        raise exceptions.InferenceError
示例#16
0
def infer_call(self, context=None):
    """infer a Call node by trying to guess what the function returns"""
    callcontext = context.clone()
    callcontext.callcontext = contextmod.CallContext(args=self.args,
                                                     keywords=self.keywords)
    callcontext.boundnode = None
    for callee in self.func.infer(context):
        if callee is util.Uninferable:
            yield callee
            continue
        try:
            if hasattr(callee, 'infer_call_result'):
                for inferred in callee.infer_call_result(self, callcontext):
                    yield inferred
        except exceptions.InferenceError:
            ## XXX log error ?
            continue
    # Explicit StopIteration to return error information, see comment
    # in raise_if_nothing_inferred.
    raise StopIteration(dict(node=self, context=context))
示例#17
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 = contextmod.InferenceContext()
    context.callcontext = contextmod.CallContext(args=[node])

    try:
        for inferred in node.igetattr("__index__", context=context):
            if not isinstance(inferred, bases.BoundMethod):
                continue

            for result in inferred.infer_call_result(node, context=context):
                if isinstance(result, nodes.Const) and isinstance(result.value, int):
                    return result
    except exceptions.InferenceError:
        pass
    return None
示例#18
0
def query_call(self: nodes.Call, context=None):
    """query a Call node by trying to guess what the function returns"""
    callcontext = contextmod.copy_context(context)
    callcontext.callcontext = contextmod.CallContext(args=self.args,
                                                     keywords=self.keywords)
    callcontext.boundnode = None
    if context is not None:
        # extra context saved the args, what's for?
        callcontext.extra_context = _populate_context_lookup(
            self, context.clone())

    res = []
    for callee in self.func.query(context):
        if callee is util.Unqueryable:
            if self.keywords is not None:
                # not implemented
                print(self.keywords)
                assert False
            for arg in self.args:
                res.extend(arg.query(context))
            continue

        if hasattr(callee, "query_end") and callee.query_end:
            res.append(callee)
            continue

        try:
            if hasattr(callee, "query_call_result"):
                for result in callee.query_call_result(caller=self,
                                                       context=callcontext):
                    if result is util.Unqueryable:
                        for arg in self.args:
                            res.extend(arg.query(context))
                    else:
                        res.append(result)

        except exceptions.InferenceError:
            continue
    return res
示例#19
0
 def from_call(cls, call_node):
     """Get a CallSite object from the given Call node."""
     callcontext = contextmod.CallContext(call_node.args,
                                          call_node.keywords)
     return cls(callcontext)