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)
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)
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))
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))
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)
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)