Esempio n. 1
0
    def igetattr(self, name, context=None):
        """Retrieve the inferred values of the given attribute name."""

        if name in self.special_attributes:
            yield self.special_attributes.lookup(name)
            return

        try:
            mro = self.super_mro()
        # Don't let invalid MROs or invalid super calls
        # leak out as is from this function.
        except exceptions.SuperError as exc:
            util.reraise(exceptions.AttributeInferenceError(
                ('Lookup for {name} on {target!r} because super call {super!r} '
                 'is invalid.'),
                target=self, attribute=name, context=context, super_=exc.super_))
        except exceptions.MroError as exc:
            util.reraise(exceptions.AttributeInferenceError(
                ('Lookup for {name} on {target!r} failed because {cls!r} has an '
                 'invalid MRO.'),
                target=self, attribute=name, context=context, mros=exc.mros,
                cls=exc.cls))
        found = False
        for cls in mro:
            if name not in cls.locals:
                continue

            found = True
            for inferred in bases._infer_stmts([cls[name]], context, frame=self):
                if not isinstance(inferred, scoped_nodes.FunctionDef):
                    yield inferred
                    continue

                # We can obtain different descriptors from a super depending
                # on what we are accessing and where the super call is.
                if inferred.type == 'classmethod':
                    yield bases.BoundMethod(inferred, cls)
                elif self._scope.type == 'classmethod' and inferred.type == 'method':
                    yield inferred
                elif self._class_based or inferred.type == 'staticmethod':
                    yield inferred
                elif bases._is_property(inferred):
                    # TODO: support other descriptors as well.
                    for value in inferred.infer_call_result(self, context):
                        yield value
                else:
                    yield bases.BoundMethod(inferred, cls)

        if not found:
            raise exceptions.AttributeInferenceError(target=self,
                                                     attribute=name,
                                                     context=context)
Esempio n. 2
0
            def infer_call_result(self, caller, context=None):
                if len(caller.args) != 2:
                    raise exceptions.InferenceError(
                        "Invalid arguments for descriptor binding",
                        target=self,
                        context=context)

                context = contextmod.copy_context(context)
                cls = next(caller.args[0].infer(context=context))

                if cls is astroid.Uninferable:
                    raise exceptions.InferenceError("Invalid class inferred",
                                                    target=self,
                                                    context=context)

                # For some reason func is a Node that the below
                # code is not expecting
                if isinstance(func, bases.BoundMethod):
                    yield func
                    return

                # Rebuild the original value, but with the parent set as the
                # class where it will be bound.
                new_func = func.__class__(name=func.name,
                                          doc=func.doc,
                                          lineno=func.lineno,
                                          col_offset=func.col_offset,
                                          parent=cls)
                # pylint: disable=no-member
                new_func.postinit(func.args, func.body, func.decorators,
                                  func.returns)

                # Build a proper bound method that points to our newly built function.
                proxy = bases.UnboundMethod(new_func)
                yield bases.BoundMethod(proxy=proxy, bound=cls)
Esempio n. 3
0
    def attr___new__(self) -> bases.BoundMethod:
        """Calling cls.__new__(type) on an object returns an instance of 'type'."""
        node: nodes.FunctionDef = builder.extract_node(
            """def __new__(self, cls): return cls()"""
        )
        # We set the parent as being the ClassDef of 'object' as that
        # triggers correct inference as a call to __new__ in bases.py
        node.parent: nodes.ClassDef = AstroidManager().builtins_module["object"]

        return bases.BoundMethod(proxy=node, bound=_get_bound_node(self))
Esempio n. 4
0
    def attr___init__(self) -> bases.BoundMethod:
        """Calling cls.__init__() normally returns None."""
        # The *args and **kwargs are necessary not to trigger warnings about missing
        # or extra parameters for '__init__' methods we don't infer correctly.
        # This BoundMethod is the fallback value for those.
        node: nodes.FunctionDef = builder.extract_node(
            """def __init__(self, *args, **kwargs): return None"""
        )
        # We set the parent as being the ClassDef of 'object' as that
        # is where this method originally comes from
        node.parent: nodes.ClassDef = AstroidManager().builtins_module["object"]

        return bases.BoundMethod(proxy=node, bound=_get_bound_node(self))
Esempio n. 5
0
            def infer_call_result(self, caller, context=None):
                if len(caller.args) != 2:
                    raise exceptions.InferenceError(
                        "Invalid arguments for descriptor binding",
                        target=self,
                        context=context)

                context = contextmod.copy_context(context)
                cls = next(caller.args[0].infer(context=context))

                # Rebuild the original value, but with the parent set as the
                # class where it will be bound.
                new_func = func.__class__(name=func.name,
                                          doc=func.doc,
                                          lineno=func.lineno,
                                          col_offset=func.col_offset,
                                          parent=cls)
                new_func.postinit(func.args, func.body, func.decorators,
                                  func.returns)

                # Build a proper bound method that points to our newly built function.
                proxy = bases.UnboundMethod(new_func)
                yield bases.BoundMethod(proxy=proxy, bound=cls)
Esempio n. 6
0
    def igetattr(self, name: str, context: InferenceContext | None = None):
        """Retrieve the inferred values of the given attribute name."""
        # '__class__' is a special attribute that should be taken directly
        # from the special attributes dict
        if name == "__class__":
            yield self.special_attributes.lookup(name)
            return

        try:
            mro = self.super_mro()
        # Don't let invalid MROs or invalid super calls
        # leak out as is from this function.
        except SuperError as exc:
            raise AttributeInferenceError(
                ("Lookup for {name} on {target!r} because super call {super!r} "
                 "is invalid."),
                target=self,
                attribute=name,
                context=context,
                super_=exc.super_,
            ) from exc
        except MroError as exc:
            raise AttributeInferenceError(
                ("Lookup for {name} on {target!r} failed because {cls!r} has an "
                 "invalid MRO."),
                target=self,
                attribute=name,
                context=context,
                mros=exc.mros,
                cls=exc.cls,
            ) from exc
        found = False
        for cls in mro:
            if name not in cls.locals:
                continue

            found = True
            for inferred in bases._infer_stmts([cls[name]],
                                               context,
                                               frame=self):
                if not isinstance(inferred, scoped_nodes.FunctionDef):
                    yield inferred
                    continue

                # We can obtain different descriptors from a super depending
                # on what we are accessing and where the super call is.
                if inferred.type == "classmethod":
                    yield bases.BoundMethod(inferred, cls)
                elif self._scope.type == "classmethod" and inferred.type == "method":
                    yield inferred
                elif self._class_based or inferred.type == "staticmethod":
                    yield inferred
                elif isinstance(inferred, Property):
                    function = inferred.function
                    try:
                        yield from function.infer_call_result(caller=self,
                                                              context=context)
                    except InferenceError:
                        yield util.Uninferable
                elif bases._is_property(inferred):
                    # TODO: support other descriptors as well.
                    try:
                        yield from inferred.infer_call_result(self, context)
                    except InferenceError:
                        yield util.Uninferable
                else:
                    yield bases.BoundMethod(inferred, cls)

        # Only if we haven't found any explicit overwrites for the
        # attribute we look it up in the special attributes
        if not found and name in self.special_attributes:
            yield self.special_attributes.lookup(name)
            return

        if not found:
            raise AttributeInferenceError(target=self,
                                          attribute=name,
                                          context=context)