def attr___subclasses__(self): """Get the subclasses of the underlying class This looks only in the current module for retrieving the subclasses, thus it might miss a couple of them. """ if not self._instance.newstyle: raise AttributeInferenceError( target=self._instance, attribute="__subclasses__" ) qname = self._instance.qname() root = self._instance.root() classes = [ cls for cls in root.nodes_of_class(nodes.ClassDef) if cls != self._instance and cls.is_subtype_of(qname, context=self.context) ] obj = node_classes.List(parent=self._instance) obj.postinit(classes) class SubclassesBoundMethod(bases.BoundMethod): def infer_call_result(self, caller, context=None): yield obj implicit_metaclass = self._instance.implicit_metaclass() subclasses_method = implicit_metaclass.locals["__subclasses__"][0] return SubclassesBoundMethod(proxy=subclasses_method, bound=implicit_metaclass)
def getattr(self, name, context=None, lookupclass=True): try: values = self._proxied.instance_attr(name, context) except AttributeInferenceError as exc: if self.special_attributes and name in self.special_attributes: return [self.special_attributes.lookup(name)] if lookupclass: # Class attributes not available through the instance # unless they are explicitly defined. return self._proxied.getattr(name, context, class_context=False) raise AttributeInferenceError(target=self, attribute=name, context=context) from exc # since we've no context information, return matching class members as # well if lookupclass: try: return values + self._proxied.getattr( name, context, class_context=False) except AttributeInferenceError: pass return values
def full_raiser(origin_func, attr, *args, **kwargs): """ Raises an AttributeInferenceError in case of access to __class_getitem__ method. Otherwise just call origin_func. """ if attr == "__class_getitem__": raise AttributeInferenceError("__class_getitem__ access is not allowed") return origin_func(attr, *args, **kwargs)
def attr___mro__(self): if not self._instance.newstyle: raise AttributeInferenceError(target=self._instance, attribute="__mro__") mro = self._instance.mro() obj = node_classes.Tuple(parent=self._instance) obj.postinit(mro) return obj
def lookup(self, name): """Look up the given *name* in the current model It should return an AST or an interpreter object, but if the name is not found, then an AttributeInferenceError will be raised. """ if name in self.attributes(): return getattr(self, IMPL_PREFIX + name) raise AttributeInferenceError(target=self._instance, attribute=name)
def _lookup_in_mro(node, name): attrs = node.locals.get(name, []) nodes = itertools.chain.from_iterable( ancestor.locals.get(name, []) for ancestor in node.ancestors(recurs=True)) values = list(itertools.chain(attrs, nodes)) if not values: raise AttributeInferenceError(attribute=name, target=node) return values
def real_name(self, asname): """get name from 'as' name""" for name, _asname in self.names: if name == "*": return asname if not _asname: name = name.split(".", 1)[0] _asname = name if asname == _asname: return name raise AttributeInferenceError( "Could not find original name for {attribute} in {target!r}", target=self, attribute=asname, )
def attr_mro(self): if not self._instance.newstyle: raise AttributeInferenceError(target=self._instance, attribute="mro") other_self = self # Cls.mro is a method and we need to return one in order to have a proper inference. # The method we're returning is capable of inferring the underlying MRO though. class MroBoundMethod(bases.BoundMethod): def infer_call_result(self, caller, context=None): yield other_self.attr___mro__ implicit_metaclass = self._instance.implicit_metaclass() mro_method = implicit_metaclass.locals["mro"][0] return MroBoundMethod(proxy=mro_method, bound=implicit_metaclass)
def lookup(node, name): """Lookup the given special method name in the given *node* If the special method was found, then a list of attributes will be returned. Otherwise, `astroid.AttributeInferenceError` is going to be raised. """ if isinstance(node, (astroid.List, astroid.Tuple, astroid.Const, astroid.Dict, astroid.Set)): return _builtin_lookup(node, name) if isinstance(node, astroid.Instance): return _lookup_in_mro(node, name) if isinstance(node, astroid.ClassDef): return _class_lookup(node, name) raise AttributeInferenceError(attribute=name, target=node)
def attr___path__(self): if not self._instance.package: raise AttributeInferenceError(target=self._instance, attribute="__path__") path_objs = [ node_classes.Const( value=path if not path.endswith("__init__.py") else os.path.dirname(path), parent=self._instance, ) for path in self._instance.path ] container = node_classes.List(parent=self._instance) container.postinit(path_objs) return container
def _builtin_lookup(node, name): values = node.locals.get(name, []) if not values: raise AttributeInferenceError(attribute=name, target=node) return values
def _class_lookup(node, name): metaclass = node.metaclass() if metaclass is None: raise AttributeInferenceError(attribute=name, target=node) return _lookup_in_mro(metaclass, name)
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 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) if not found: raise AttributeInferenceError(target=self, attribute=name, context=context)