def infer_subscript(self, context=None): """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]""" if isinstance(self.slice, nodes.Index): index = self.slice.value.infer(context).next() if index is YES: yield YES return try: if hasattr(self.value, "getitem"): assigned = self.value.getitem(index.value, context) for infered in assigned.infer(context): yield infered return else: has_infer_item = False for l in self.value.infer(): if l is not YES and hasattr(l, "infer_item"): has_infer_item = True for inferred in l.infer_item(index, context): yield inferred if not has_infer_item: raise InferenceError() except AttributeError: raise InferenceError() except (IndexError, TypeError): yield YES return else: raise InferenceError()
def infer_global(self, context=None): if context.lookupname is None: raise InferenceError() try: return _infer_stmts(self.root().getattr(context.lookupname), context) except NotFoundError: raise InferenceError()
def infer_from(self, context=None, asname=True): """infer a From nodes: return the imported module/object""" name = context.lookupname if name is None: raise InferenceError() if asname: name = self.real_name(name) module = self.do_import_module(self.modname) try: context = copy_context(context) context.lookupname = name return _infer_stmts(module.getattr(name), context) except NotFoundError: raise InferenceError(name)
def igetattr(self, name, context=None): """inferred getattr""" if hasattr(self._proxied, "attr_types") and name in self._proxied.attr_types: yield self._proxied.attr_types[name] return found = False try: # XXX frame should be self._proxied, or not ? get_attr = self.getattr(name, context, lookupclass=False) for inferred in bases._infer_stmts(self._wrap_attr( get_attr, context), context, frame=self): yield inferred found = True except (NotFoundError, InferenceError): pass try: # fallback to class'igetattr since it has some logic to handle # descriptors for inferred in self._wrap_attr( self._proxied.igetattr(name, context), context): yield inferred found = True except (NotFoundError, InferenceError): pass if not found: raise InferenceError(name)
def wrapper(*args, **kwargs): infered = False for node in func(*args, **kwargs): infered = True yield node if not infered: raise InferenceError()
def _infer_stmts(stmts, context, frame=None): """return an iterator on statements inferred by each statement in <stmts> """ stmt = None infered = False if context is not None: name = context.lookupname context = context.clone() else: name = None context = InferenceContext() for stmt in stmts: if stmt is YES: yield stmt infered = True continue context.lookupname = stmt._infer_name(frame, name) try: for infered in stmt.infer(context): yield infered infered = True except UnresolvableName: continue except InferenceError: yield YES infered = True if not infered: raise InferenceError(str(stmt))
def igetattr(self, name, context=None): """inferred getattr, need special treatment in class to handle descriptors """ # set lookup name since this is necessary to infer on import nodes for # instance context = copy_context(context) context.lookupname = name try: for infered in _infer_stmts(self.getattr(name, context), context, frame=self): # yield YES object instead of descriptors when necessary if not isinstance(infered, Const) and isinstance(infered, Instance): try: infered._proxied.getattr('__get__', context) except NotFoundError: yield infered else: yield YES else: yield function_to_method(infered, self) except NotFoundError: if not name.startswith('__') and self.has_dynamic_getattr(context): # class handle some dynamic attributes, return a YES object yield YES else: raise InferenceError(name)
def infer_call_result(self, caller, context=None): """infer what a class instance is returning when called""" infered = False for node in self._proxied.igetattr('__call__', context): for res in node.infer_call_result(caller, context): infered = True yield res if not infered: raise InferenceError()
def infer_import(self, context=None, asname=True): """infer an Import node: return the imported module/object""" name = context.lookupname if name is None: raise InferenceError() if asname: yield self.do_import_module(self.real_name(name)) else: yield self.do_import_module(name)
def infer_subscript(self, context=None): """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]""" if isinstance(self.slice, nodes.Index): index = self.slice.value.infer(context).next() if index is YES: yield YES return try: # suppose it's a Tuple/List node (attribute error else) assigned = self.value.getitem(index.value, context) except AttributeError: raise InferenceError() except (IndexError, TypeError): yield YES return for infered in assigned.infer(context): yield infered else: raise InferenceError()
def igetattr(self, name, context=None): """inferred getattr""" # set lookup name since this is necessary to infer on import nodes for # instance context = copy_context(context) context.lookupname = name try: return _infer_stmts(self.getattr(name, context), context, frame=self) except NotFoundError: raise InferenceError(name)
def do_import_module(self, modname): """return the ast for a module whose name is <modname> imported by <self> """ # handle special case where we are on a package node importing a module # using the same name as the package, which may end in an infinite loop # on relative imports # XXX: no more needed ? mymodule = self.root() level = getattr(self, 'level', None) # Import as no level # XXX we should investigate deeper if we really want to check # importing itself: modname and mymodule.name be relative or absolute if mymodule.relative_to_absolute_name(modname, level) == mymodule.name: # FIXME: we used to raise InferenceError here, but why ? return mymodule try: return mymodule.import_module(modname, level=level) except ASTNGBuildingException: raise InferenceError(modname) except SyntaxError, ex: raise InferenceError(str(ex))
def infer_subscript(self, context=None): """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]""" value = self.value.infer(context).next() if value is YES: yield YES return index = self.slice.infer(context).next() if index is YES: yield YES return if isinstance(index, nodes.Const): try: assigned = value.getitem(index.value, context) except AttributeError: raise InferenceError() except (IndexError, TypeError): yield YES return for infered in assigned.infer(context): yield infered else: raise InferenceError()
def igetattr(self, name, context=None): """inferred getattr""" try: # 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 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 NotFoundError: raise InferenceError(name)
def interfaces(self, herited=True, handler_func=_iface_hdlr): """return an iterator on interfaces implemented by the given class node """ # FIXME: what if __implements__ = (MyIFace, MyParent.__implements__)... try: implements = Instance(self).getattr('__implements__')[0] except NotFoundError: return if not herited and not implements.frame() is self: return found = set() missing = False for iface in unpack_infer(implements): if iface is YES: missing = True continue if not iface in found and handler_func(iface): found.add(iface) yield iface if missing: raise InferenceError()
def infer_arguments(self, context=None): name = context.lookupname if name is None: raise InferenceError() return _arguments_infer_argname(self, name, context)
def infer(self, context=None): """we don't know how to resolve a statement by default""" # this method is overridden by most concrete classes raise InferenceError(self.__class__.__name__)
def infer_argument(self, funcnode, name, context): """infer a function argument value according to the call context""" # 1. search in named keywords try: return self.nargs[name].infer(context) except KeyError: # Function.args.args can be None in astng (means that we don't have # information on argnames) argindex = funcnode.args.find_argname(name)[0] if argindex is not None: # 2. first argument of instance/class method if argindex == 0 and funcnode.type in ('method', 'classmethod'): if context.boundnode is not None: boundnode = context.boundnode else: # XXX can do better ? boundnode = funcnode.parent.frame() if funcnode.type == 'method': if not isinstance(boundnode, Instance): boundnode = Instance(boundnode) return iter((boundnode, )) if funcnode.type == 'classmethod': return iter((boundnode, )) # 2. search arg index try: return self.args[argindex].infer(context) except IndexError: pass # 3. search in *args (.starargs) if self.starargs is not None: its = [] for infered in self.starargs.infer(context): if infered is YES: its.append((YES, )) continue try: its.append( infered.getitem(argindex, context).infer(context)) except (InferenceError, AttributeError): its.append((YES, )) except (IndexError, TypeError): continue if its: return chain(*its) # 4. XXX search in **kwargs (.dstarargs) if self.dstarargs is not None: its = [] for infered in self.dstarargs.infer(context): if infered is YES: its.append((YES, )) continue try: its.append(infered.getitem(name, context).infer(context)) except (InferenceError, AttributeError): its.append((YES, )) except (IndexError, TypeError): continue if its: return chain(*its) # 5. */** argument, (Tuple or Dict) if name == funcnode.args.vararg: return iter((nodes.const_factory(()))) if name == funcnode.args.kwarg: return iter((nodes.const_factory({}))) # 6. return default value if any try: return funcnode.args.default_value(name).infer(context) except NoDefault: raise InferenceError(name)