Пример #1
0
def _infer_stmts(stmts, context, frame=None):
    """Return an iterator on statements inferred by each statement in *stmts*."""
    inferred = False
    if context is not None:
        name = context.lookupname
        context = context.clone()
    else:
        name = None
        context = contextmod.InferenceContext()

    for stmt in stmts:
        if stmt is util.Uninferable:
            yield stmt
            inferred = True
            continue
        context.lookupname = stmt._infer_name(frame, name)
        try:
            for inferred in stmt.infer(context=context):
                yield inferred
                inferred = True
        except exceptions.NameInferenceError:
            continue
        except exceptions.InferenceError:
            yield util.Uninferable
            inferred = True
    if not inferred:
        raise exceptions.InferenceError(
            "Inference failed for all members of {stmts!r}.",
            stmts=stmts,
            frame=frame,
            context=context,
        )
Пример #2
0
def _infer_augassign(self, context=None):
    """Inference logic for augmented binary operations."""
    if context is None:
        context = contextmod.InferenceContext()

    for lhs in self.target.infer_lhs(context=context):
        if lhs is util.Uninferable:
            # Don't know how to process this.
            yield util.Uninferable
            return

        # TODO(cpopa): if we have A() * A(), trying to infer
        # the rhs with the same context will result in an
        # inference error, so we create another context for it.
        # This is a bug which should be fixed in InferenceContext at some point.
        rhs_context = context.clone()
        rhs_context.path = set()
        for rhs in self.value.infer(context=rhs_context):
            if rhs is util.Uninferable:
                # Don't know how to process this.
                yield util.Uninferable
                return

            try:
                results = _infer_binary_operation(lhs, rhs, self, context,
                                                  _get_aug_flow)
            except exceptions._NonDeducibleTypeHierarchy:
                yield util.Uninferable
            else:
                for result in results:
                    yield result
Пример #3
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))
Пример #4
0
def _infer_binop(self, context):
    """Binary operation inferrence logic."""
    if context is None:
        context = contextmod.InferenceContext()
    left = self.left
    right = self.right

    # we use two separate contexts for evaluating lhs and rhs because
    # 1. evaluating lhs may leave some undesired entries in context.path
    #    which may not let us infer right value of rhs
    lhs_context = context.clone()
    rhs_context = context.clone()

    for lhs in left.infer(context=lhs_context):
        if lhs is util.Uninferable:
            # Don't know how to process this.
            yield util.Uninferable
            return

        for rhs in right.infer(context=rhs_context):
            if rhs is util.Uninferable:
                # Don't know how to process this.
                yield util.Uninferable
                return

            try:
                results = _infer_binary_operation(lhs, rhs, self, context,
                                                  _get_binop_flow)
            except exceptions._NonDeducibleTypeHierarchy:
                yield util.Uninferable
            else:
                for result in results:
                    yield result
Пример #5
0
    def igetattr(self, name, context=None):
        """inferred getattr"""
        if not context:
            context = contextmod.InferenceContext()
        try:
            # avoid recursively inferring the same attr on the same class
            if context.push((self._proxied, name)):
                return

            # XXX frame should be self._proxied, or not ?
            get_attr = self.getattr(name, context, lookupclass=False)
            for stmt in _infer_stmts(self._wrap_attr(get_attr, context),
                                     context,
                                     frame=self):
                yield stmt
        except exceptions.AttributeInferenceError:
            try:
                # fallback to class.igetattr since it has some logic to handle
                # descriptors
                attrs = self._proxied.igetattr(name,
                                               context,
                                               class_context=False)
                for stmt in self._wrap_attr(attrs, context):
                    yield stmt
            except exceptions.AttributeInferenceError as error:
                util.reraise(exceptions.InferenceError(**vars(error)))
Пример #6
0
def _query_augassign(self, context=None):
    """query logic for augmented binary operations."""
    if context is None:
        context = contextmod.InferenceContext()

    rhs_context = context.clone()

    lhs_res = self.target.query_lhs(context=context)
    rhs_res = self.value.query(context=rhs_context)
    res = []
    for lhs, rhs in itertools.product(lhs_res, rhs_res):
        if any(value is util.Unqueryable for value in (rhs, lhs)):
            # Don't know how to process this.
            continue
            # return util.Unqueryable

        try:
            result = _query_binary_operation(
                left=lhs,
                right=rhs,
                binary_opnode=self,
                context=context,
                # flow_factory=_get_aug_flow,
            )
            res.extend(result)
        except exceptions._NonDeducibleTypeHierarchy:
            continue
    return res
Пример #7
0
    def igetattr(self, name, context=None):
        """inferred getattr"""
        if not context:
            context = contextmod.InferenceContext()
        try:
            # avoid recursively inferring the same attr on the same class
            if context.push((self._proxied, name)):
                return

            # XXX frame should be self._proxied, or not ?
            get_attr = self.getattr(name, context, lookupclass=False)
            yield from _infer_stmts(self._wrap_attr(get_attr, context),
                                    context,
                                    frame=self)
        except exceptions.AttributeInferenceError as error:
            try:
                # fallback to class.igetattr since it has some logic to handle
                # descriptors
                # But only if the _proxied is the Class.
                if self._proxied.__class__.__name__ != "ClassDef":
                    raise exceptions.InferenceError(**vars(error)) from error
                attrs = self._proxied.igetattr(name,
                                               context,
                                               class_context=False)
                yield from self._wrap_attr(attrs, context)
            except exceptions.AttributeInferenceError as error:
                raise exceptions.InferenceError(**vars(error)) from error
Пример #8
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
Пример #9
0
    def wrapped(node, context=None, _func=func, **kwargs):
        """wrapper function handling context"""
        if context is None:
            context = contextmod.InferenceContext()
        if context.push(node):
            return None

        yielded = set()
        generator = _func(node, context, **kwargs)
        while True:
            try:
                res = next(generator)
            except StopIteration as error:
                if error.args:
                    return error.args[0]
                return None

            # unproxy only true instance, not const, tuple, dict...
            if res.__class__.__name__ == "Instance":
                ares = res._proxied
            else:
                ares = res
            if ares not in yielded:
                yield res
                yielded.add(ares)
Пример #10
0
def _infer_augassign(self, context=None):
    """Inference logic for augmented binary operations."""
    if context is None:
        context = contextmod.InferenceContext()

    rhs_context = context.clone()

    lhs_iter = self.target.infer_lhs(context=context)
    rhs_iter = self.value.infer(context=rhs_context)
    for lhs, rhs in itertools.product(lhs_iter, rhs_iter):
        if any(value is util.Uninferable for value in (rhs, lhs)):
            # Don't know how to process this.
            yield util.Uninferable
            return

        try:
            yield from _infer_binary_operation(
                left=lhs,
                right=rhs,
                binary_opnode=self,
                context=context,
                flow_factory=_get_aug_flow,
            )
        except exceptions._NonDeducibleTypeHierarchy:
            yield util.Uninferable
Пример #11
0
    def wrapped(node, context=None, _func=func, **kwargs):
        """wrapper function handling context"""
        if context is None:
            context = contextmod.InferenceContext()
        if context.push(node):
            return None

        yielded = set()
        generator = _func(node, context, **kwargs)
        try:
            while True:
                res = next(generator)
                # unproxy only true instance, not const, tuple, dict...
                if res.__class__.__name__ == 'Instance':
                    ares = res._proxied
                else:
                    ares = res
                if ares not in yielded:
                    yield res
                    yielded.add(ares)
        except StopIteration as error:
            # Explicit StopIteration to return error information, see
            # comment in raise_if_nothing_inferred.
            if error.args:
                return error.args[0]
            return None
Пример #12
0
def infer_ifexp(self, context=None):
    """Support IfExp inference

    If we can't infer the truthiness of the condition, we default
    to inferring both branches. Otherwise, we infer either branch
    depending on the condition.
    """
    both_branches = False
    # We use two separate contexts for evaluating lhs and rhs because
    # evaluating lhs may leave some undesired entries in context.path
    # which may not let us infer right value of rhs.

    context = context or contextmod.InferenceContext()
    lhs_context = contextmod.copy_context(context)
    rhs_context = contextmod.copy_context(context)
    try:
        test = next(self.test.infer(context=context.clone()))
    except exceptions.InferenceError:
        both_branches = True
    else:
        if test is not util.Uninferable:
            if test.bool_value():
                yield from self.body.infer(context=lhs_context)
            else:
                yield from self.orelse.infer(context=rhs_context)
        else:
            both_branches = True
    if both_branches:
        yield from self.body.infer(context=lhs_context)
        yield from self.orelse.infer(context=rhs_context)
Пример #13
0
    def ilookup(self, name):
        """inferred lookup

        return an iterator on inferred values of the statements returned by
        the lookup method
        """
        frame, stmts = self.lookup(name)
        context = contextmod.InferenceContext()
        return bases._infer_stmts(stmts, context, frame)
Пример #14
0
 def test_absolute_import(self):
     module = resources.build_file('data/absimport.py')
     ctx = contextmod.InferenceContext()
     # will fail if absolute import failed
     ctx.lookupname = 'message'
     next(module['message'].infer(ctx))
     ctx.lookupname = 'email'
     m = next(module['email'].infer(ctx))
     self.assertFalse(m.file.startswith(os.path.join('data', 'email.py')))
Пример #15
0
 def test_absolute_import(self):
     module = resources.build_file("data/absimport.py")
     ctx = contextmod.InferenceContext()
     # will fail if absolute import failed
     ctx.lookupname = "message"
     next(module["message"].infer(ctx))
     ctx.lookupname = "email"
     m = next(module["email"].infer(ctx))
     self.assertFalse(m.file.startswith(os.path.join("data", "email.py")))
Пример #16
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)
Пример #17
0
def starred_assigned_stmts(self, node=None, context=None, asspath=None):
    stmt = self.statement()
    if not isinstance(stmt, (nodes.Assign, nodes.For)):
        raise exceptions.InferenceError()

    if isinstance(stmt, nodes.Assign):
        value = stmt.value
        lhs = stmt.targets[0]

        if sum(1 for node in lhs.nodes_of_class(nodes.Starred)) > 1:
            # Too many starred arguments in the expression.
            raise exceptions.InferenceError()

        if context is None:
            context = contextmod.InferenceContext()
        try:
            rhs = next(value.infer(context))
        except exceptions.InferenceError:
            yield util.YES
            return
        if rhs is util.YES or not hasattr(rhs, 'elts'):
            # Not interested in inferred values without elts.
            yield util.YES
            return

        elts = collections.deque(rhs.elts[:])
        if len(lhs.elts) > len(rhs.elts):
            # a, *b, c = (1, 2)
            raise exceptions.InferenceError()

        # Unpack iteratively the values from the rhs of the assignment,
        # until the find the starred node. What will remain will
        # be the list of values which the Starred node will represent
        # This is done in two steps, from left to right to remove
        # anything before the starred node and from right to left
        # to remvoe anything after the starred node.

        for index, node in enumerate(lhs.elts):
            if not isinstance(node, nodes.Starred):
                elts.popleft()
                continue
            lhs_elts = collections.deque(reversed(lhs.elts[index:]))
            for node in lhs_elts:
                if not isinstance(node, nodes.Starred):
                    elts.pop()
                    continue
                # We're done
                packed = nodes.List()
                packed.elts = elts
                packed.parent = self
                yield packed
                break
Пример #18
0
    def wrapped(node, context=None, _func=func, **kwargs):
        """wrapper function handling context"""
        if context is None:
            context = contextmod.InferenceContext()
        if context.push(node):
            return None

        try:
            return _func(node, context, **kwargs)
        except StopIteration as error:
            if error.args:
                return error.args[0]
            return None
Пример #19
0
 def wrapped(node, context=None, _func=func, **kwargs):
     """wrapper function handling context"""
     if context is None:
         context = contextmod.InferenceContext()
     context.push(node)
     yielded = set()
     for res in _func(node, context, **kwargs):
         # unproxy only true instance, not const, tuple, dict...
         if res.__class__ is Instance:
             ares = res._proxied
         else:
             ares = res
         if ares not in yielded:
             yield res
             yielded.add(ares)
Пример #20
0
def query_attribute(self, context=None):
    """query an Attribute node by using getattr on the associated object"""
    res = []
    for owner in self.expr.query(context):
        if owner is util.Uninferable:
            assert False

        if owner is util.Unqueryable:
            continue

        if owner.query_end:
            res.extend([owner, util.Unqueryable])
            continue

        if context and context.boundnode:
            # This handles the situation where the attribute is accessed through a subclass
            # of a base class and the attribute is defined at the base class's level,
            # by taking in consideration a redefinition in the subclass.
            if isinstance(owner, bases.Instance) and isinstance(
                    context.boundnode, bases.Instance):
                try:
                    if helpers.is_subtype(
                            helpers.object_type(context.boundnode),
                            helpers.object_type(owner),
                    ):
                        owner = context.boundnode
                except exceptions._NonDeducibleTypeHierarchy:
                    # Can't determine anything useful.
                    pass
        elif not context:
            context = contextmod.InferenceContext()

        try:
            context.boundnode = owner
            res.extend(owner.query_attr(self.attrname, context))
        except (
                exceptions.AttributeInferenceError,
                exceptions.InferenceError,
                AttributeError,
        ):
            import traceback
            traceback.print_exc()
            pass
        finally:
            context.boundnode = None
    if len(res) == 0:
        return [util.Unqueryable]
    return res
Пример #21
0
def _object_type(node, context=None):
    astroid_manager = manager.AstroidManager()
    builtins = astroid_manager.builtins_module
    context = context or contextmod.InferenceContext()

    for inferred in node.infer(context=context):
        if isinstance(inferred, scoped_nodes.ClassDef):
            if inferred.newstyle:
                metaclass = inferred.metaclass(context=context)
                if metaclass:
                    yield metaclass
                    continue
            yield builtins.getattr("type")[0]
        elif isinstance(inferred, (scoped_nodes.Lambda, bases.UnboundMethod)):
            yield _function_type(inferred, builtins)
        elif isinstance(inferred, scoped_nodes.Module):
            yield _build_proxy_class("module", builtins)
        else:
            yield inferred._proxied
Пример #22
0
    def infer_call_result(self, caller, context=None):
        if context is None:
            context = contextmod.InferenceContext()
        context = context.clone()
        context.boundnode = self.bound

        if (self.bound.__class__.__name__ == 'ClassDef'
                and self.bound.name == 'type' and self.name == '__new__'
                and len(caller.args) == 4
                # TODO(cpopa): this check shouldn't be needed.
                and self._proxied.parent.frame().qname()
                == '%s.object' % BUILTINS):

            # Check if we have an ``type.__new__(mcs, name, bases, attrs)`` call.
            new_cls = self._infer_type_new_call(caller, context)
            if new_cls:
                return iter((new_cls, ))

        return super(BoundMethod, self).infer_call_result(caller, context)
Пример #23
0
    def _unpack_keywords(self, keywords, context=None):
        values = {}
        context = context or contextmod.InferenceContext()
        context.extra_context = self.argument_context_map
        for name, value in keywords:
            if name is None:
                # Then it's an unpacking operation (**)
                try:
                    inferred = next(value.infer(context=context))
                except InferenceError:
                    values[name] = util.Uninferable
                    continue
                except StopIteration:
                    continue

                if not isinstance(inferred, nodes.Dict):
                    # Not something we can work with.
                    values[name] = util.Uninferable
                    continue

                for dict_key, dict_value in inferred.items:
                    try:
                        dict_key = next(dict_key.infer(context=context))
                    except InferenceError:
                        values[name] = util.Uninferable
                        continue
                    except StopIteration:
                        continue
                    if not isinstance(dict_key, nodes.Const):
                        values[name] = util.Uninferable
                        continue
                    if not isinstance(dict_key.value, str):
                        values[name] = util.Uninferable
                        continue
                    if dict_key.value in values:
                        # The name is already in the dictionary
                        values[dict_key.value] = util.Uninferable
                        self.duplicated_keywords.add(dict_key.value)
                        continue
                    values[dict_key.value] = dict_value
            else:
                values[name] = value
        return values
Пример #24
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
Пример #25
0
    def _unpack_args(args):
        values = []
        context = contextmod.InferenceContext()
        for arg in args:
            if isinstance(arg, nodes.Starred):
                try:
                    inferred = next(arg.value.infer(context=context))
                except exceptions.InferenceError:
                    values.append(util.Uninferable)
                    continue

                if inferred is util.Uninferable:
                    values.append(util.Uninferable)
                    continue
                if not hasattr(inferred, 'elts'):
                    values.append(util.Uninferable)
                    continue
                values.extend(inferred.elts)
            else:
                values.append(arg)
        return values
Пример #26
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
Пример #27
0
    def _unpack_args(self, args, context=None):
        values = []
        context = context or contextmod.InferenceContext()
        context.extra_context = self.argument_context_map
        for arg in args:
            if isinstance(arg, nodes.Starred):
                try:
                    inferred = next(arg.value.infer(context=context))
                except exceptions.InferenceError:
                    values.append(util.Uninferable)
                    continue

                if inferred is util.Uninferable:
                    values.append(util.Uninferable)
                    continue
                if not hasattr(inferred, "elts"):
                    values.append(util.Uninferable)
                    continue
                values.extend(inferred.elts)
            else:
                values.append(arg)
        return values
Пример #28
0
 def igetattr(self, name, context=None):
     """inferred getattr"""
     if not context:
         context = contextmod.InferenceContext()
     try:
         # avoid recursively inferring the same attr on the same class
         context.push((self._proxied, name))
         # XXX frame should be self._proxied, or not ?
         get_attr = self.getattr(name, context, lookupclass=False)
         return _infer_stmts(
             self._wrap_attr(get_attr, context),
             context,
             frame=self,
         )
     except exceptions.NotFoundError:
         try:
             # fallback to class'igetattr since it has some logic to handle
             # descriptors
             return self._wrap_attr(self._proxied.igetattr(name, context),
                                    context)
         except exceptions.NotFoundError:
             raise exceptions.InferenceError(name)
Пример #29
0
def _infer_augassign(self, context=None):
    """Inference logic for augmented binary operations."""
    if context is None:
        context = contextmod.InferenceContext()

    for lhs in self.target.infer_lhs(context=context):
        if lhs is util.Uninferable:
            # Don't know how to process this.
            yield util.Uninferable
            return

        rhs_context = context.clone()
        for rhs in self.value.infer(context=rhs_context):
            if rhs is util.Uninferable:
                # Don't know how to process this.
                yield util.Uninferable
                return

            try:
                yield from _infer_binary_operation(lhs, rhs, self, context, _get_aug_flow)
            except exceptions._NonDeducibleTypeHierarchy:
                yield util.Uninferable
Пример #30
0
def infer_attribute(self, context=None):
    """infer an Attribute node by using getattr on the associated object"""
    for owner in self.expr.infer(context):
        if owner is util.Uninferable:
            yield owner
            continue

        if context and context.boundnode:
            # This handles the situation where the attribute is accessed through a subclass
            # of a base class and the attribute is defined at the base class's level,
            # by taking in consideration a redefinition in the subclass.
            if isinstance(owner, bases.Instance) and isinstance(
                context.boundnode, bases.Instance
            ):
                try:
                    if helpers.is_subtype(
                        helpers.object_type(context.boundnode),
                        helpers.object_type(owner),
                    ):
                        owner = context.boundnode
                except _NonDeducibleTypeHierarchy:
                    # Can't determine anything useful.
                    pass
        elif not context:
            context = contextmod.InferenceContext()

        old_boundnode = context.boundnode
        try:
            context.boundnode = owner
            yield from owner.igetattr(self.attrname, context)
        except (
            AttributeInferenceError,
            InferenceError,
            AttributeError,
        ):
            pass
        finally:
            context.boundnode = old_boundnode
    return dict(node=self, context=context)