def test_getattr_method_transform(self): data = ''' class Clazz(object): def m1(self, value): self.value = value m2 = m1 def func(arg1, arg2): "function that will be used as a method" return arg1.value + arg2 Clazz.m3 = func inst = Clazz() inst.m4 = func ''' astroid = abuilder.string_build(data, __name__, __file__) cls = astroid['Clazz'] # test del statement not returned by getattr for method in ('m1', 'm2', 'm3'): inferred = list(cls.igetattr(method)) self.assertEqual(len(inferred), 1) self.assertIsInstance(inferred[0], UnboundMethod) inferred = list(Instance(cls).igetattr(method)) self.assertEqual(len(inferred), 1) self.assertIsInstance(inferred[0], BoundMethod) inferred = list(Instance(cls).igetattr('m4')) self.assertEqual(len(inferred), 1) self.assertIsInstance(inferred[0], nodes.Function)
def test_instance_getattr(self): data = ''' class WebAppObject(object): def __init__(self, application): self.appli = application self.appli += 2 del self.appli ''' astroid = abuilder.string_build(data, __name__, __file__) inst = Instance(astroid['WebAppObject']) # test del statement not returned by getattr self.assertEqual(len(inst.getattr('appli')), 2)
def test_instance_getattr(self): data = ''' class WebAppObject(object): def __init__(self, application): self.appli = application self.appli += 2 del self.appli ''' astroid = test_utils.build_module(data) inst = Instance(astroid['WebAppObject']) # test del statement not returned by getattr self.assertEqual(len(inst.getattr('appli')), 2)
def test_nonregr_func_global(self): code = ''' active_application = None def get_active_application(): global active_application return active_application class Application(object): def __init__(self): global active_application active_application = self class DataManager(object): def __init__(self, app=None): self.app = get_active_application() def test(self): p = self.app print (p) ''' astroid = builder.string_build(code, __name__, __file__) infered = list(Instance(astroid['DataManager']).igetattr('app')) self.assertEqual(len(infered), 2, infered) # None / Instance(Application) infered = list( get_name_node(astroid['DataManager']['test'], 'p').infer()) self.assertEqual(len(infered), 2, infered) for node in infered: if isinstance(node, Instance) and node.name == 'Application': break else: self.fail('expected to find an instance of Application in %s' % infered)
def _arguments_infer_argname(self, name, context): # arguments information may be missing, in which case we can't do anything # more if not (self.args or self.vararg or self.kwarg): yield YES return # first argument of instance/class method if self.args and getattr(self.args[0], 'name', None) == name: functype = self.parent.type if functype == 'method': yield Instance(self.parent.parent.frame()) return if functype == 'classmethod': yield self.parent.parent.frame() return if name == self.vararg: yield const_factory(()) return if name == self.kwarg: yield const_factory({}) return # if there is a default value, yield it. And then yield YES to reflect # we can't guess given argument value try: context = copy_context(context) for infered in self.default_value(name).infer(context): yield infered yield YES except NoDefault: yield YES
def test_instance_special_attributes(self): for inst in (Instance(MODULE['YO']), nodes.List(), nodes.Const(1)): self.assertRaises(NotFoundError, inst.getattr, '__mro__') self.assertRaises(NotFoundError, inst.getattr, '__bases__') self.assertRaises(NotFoundError, inst.getattr, '__name__') self.assertEqual(len(inst.getattr('__dict__')), 1) self.assertEqual(len(inst.getattr('__doc__')), 1)
def infer_call_result(self, caller, context=None): """infer what a class is returning when called""" if self._is_subtype_of('%s.type' % (BUILTINS, )) and len(caller.args) == 3: name_node = caller.args[0].infer().next() if isinstance(name_node, Const) and isinstance( name_node.value, basestring): name = name_node.value else: yield YES return result = Class(name, None) bases = caller.args[1].infer().next() if isinstance(bases, (Tuple, List)): result.bases = bases.itered() else: # There is currently no AST node that can represent an 'unknown' # node (YES is not an AST node), therefore we simply return YES here # although we know at least the name of the class. yield YES return result.parent = caller.parent yield result else: yield Instance(self)
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 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 test_instance_getattr_with_class_attr(self): data = ''' class Parent: aa = 1 cc = 1 class Klass(Parent): aa = 0 bb = 0 def incr(self, val): self.cc = self.aa if val > self.aa: val = self.aa if val < self.bb: val = self.bb self.aa += val ''' astroid = test_utils.build_module(data) inst = Instance(astroid['Klass']) self.assertEqual(len(inst.getattr('aa')), 3, inst.getattr('aa')) self.assertEqual(len(inst.getattr('bb')), 1, inst.getattr('bb')) self.assertEqual(len(inst.getattr('cc')), 2, inst.getattr('cc'))
def test_instance_getattr_with_class_attr(self): data = ''' class Parent: aa = 1 cc = 1 class Klass(Parent): aa = 0 bb = 0 def incr(self, val): self.cc = self.aa if val > self.aa: val = self.aa if val < self.bb: val = self.bb self.aa += val ''' astroid = abuilder.string_build(data, __name__, __file__) inst = Instance(astroid['Klass']) self.assertEqual(len(inst.getattr('aa')), 3, inst.getattr('aa')) self.assertEqual(len(inst.getattr('bb')), 1, inst.getattr('bb')) self.assertEqual(len(inst.getattr('cc')), 2, inst.getattr('cc'))
def test_instance_getattr_with_class_attr(self): data = """ class Parent: aa = 1 cc = 1 class Klass(Parent): aa = 0 bb = 0 def incr(self, val): self.cc = self.aa if val > self.aa: val = self.aa if val < self.bb: val = self.bb self.aa += val """ astroid = abuilder.string_build(data, __name__, __file__) inst = Instance(astroid["Klass"]) self.assertEqual(len(inst.getattr("aa")), 3, inst.getattr("aa")) self.assertEqual(len(inst.getattr("bb")), 1, inst.getattr("bb")) self.assertEqual(len(inst.getattr("cc")), 2, inst.getattr("cc"))
def excepthandler_assigned_stmts(self, node, context=None, asspath=None): for assigned in unpack_infer(self.type): if isinstance(assigned, nodes.Class): assigned = Instance(assigned) yield assigned
def instanciate_class(self): """return Instance of Class node, else return self""" return Instance(self)
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 astroid (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,)) # if we have a method, extract one position # from the index, so we'll take in account # the extra parameter represented by `self` or `cls` if funcnode.type in ('method', 'classmethod'): argindex -= 1 # 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)
def infer_call_result(self, caller, context=None): """infer what a class is returning when called""" yield Instance(self)