0001 # Tests some corner cases with isinstance() and issubclass(). While these 0002 # tests use new style classes and properties, they actually do whitebox 0003 # testing of error conditions uncovered when using extension types. 0004 0005 import unittest 0006 from test import test_support 0007 import sys 0008 0009 0010 0011 class TestIsInstanceExceptions(unittest.TestCase): 0012 # Test to make sure that an AttributeError when accessing the instance's 0013 # class's bases is masked. This was actually a bug in Python 2.2 and 0014 # 2.2.1 where the exception wasn't caught but it also wasn't being cleared 0015 # (leading to an "undetected error" in the debug build). Set up is, 0016 # isinstance(inst, cls) where: 0017 # 0018 # - inst isn't an InstanceType 0019 # - cls isn't a ClassType, a TypeType, or a TupleType 0020 # - cls has a __bases__ attribute 0021 # - inst has a __class__ attribute 0022 # - inst.__class__ as no __bases__ attribute 0023 # 0024 # Sounds complicated, I know, but this mimics a situation where an 0025 # extension type raises an AttributeError when its __bases__ attribute is 0026 # gotten. In that case, isinstance() should return False. 0027 def test_class_has_no_bases(self): 0028 class I(object): 0029 def getclass(self): 0030 # This must return an object that has no __bases__ attribute 0031 return None 0032 __class__ = property(getclass) 0033 0034 class C(object): 0035 def getbases(self): 0036 return () 0037 __bases__ = property(getbases) 0038 0039 self.assertEqual(False, isinstance(I(), C())) 0040 0041 # Like above except that inst.__class__.__bases__ raises an exception 0042 # other than AttributeError 0043 def test_bases_raises_other_than_attribute_error(self): 0044 class E(object): 0045 def getbases(self): 0046 raise RuntimeError 0047 __bases__ = property(getbases) 0048 0049 class I(object): 0050 def getclass(self): 0051 return E() 0052 __class__ = property(getclass) 0053 0054 class C(object): 0055 def getbases(self): 0056 return () 0057 __bases__ = property(getbases) 0058 0059 self.assertRaises(RuntimeError, isinstance, I(), C()) 0060 0061 # Here's a situation where getattr(cls, '__bases__') raises an exception. 0062 # If that exception is not AttributeError, it should not get masked 0063 def test_dont_mask_non_attribute_error(self): 0064 class I: pass 0065 0066 class C(object): 0067 def getbases(self): 0068 raise RuntimeError 0069 __bases__ = property(getbases) 0070 0071 self.assertRaises(RuntimeError, isinstance, I(), C()) 0072 0073 # Like above, except that getattr(cls, '__bases__') raises an 0074 # AttributeError, which /should/ get masked as a TypeError 0075 def test_mask_attribute_error(self): 0076 class I: pass 0077 0078 class C(object): 0079 def getbases(self): 0080 raise AttributeError 0081 __bases__ = property(getbases) 0082 0083 self.assertRaises(TypeError, isinstance, I(), C()) 0084 0085 0086 0087 # These tests are similar to above, but tickle certain code paths in 0088 # issubclass() instead of isinstance() -- really PyObject_IsSubclass() 0089 # vs. PyObject_IsInstance(). 0090 class TestIsSubclassExceptions(unittest.TestCase): 0091 def test_dont_mask_non_attribute_error(self): 0092 class C(object): 0093 def getbases(self): 0094 raise RuntimeError 0095 __bases__ = property(getbases) 0096 0097 class S(C): pass 0098 0099 self.assertRaises(RuntimeError, issubclass, C(), S()) 0100 0101 def test_mask_attribute_error(self): 0102 class C(object): 0103 def getbases(self): 0104 raise AttributeError 0105 __bases__ = property(getbases) 0106 0107 class S(C): pass 0108 0109 self.assertRaises(TypeError, issubclass, C(), S()) 0110 0111 # Like above, but test the second branch, where the __bases__ of the 0112 # second arg (the cls arg) is tested. This means the first arg must 0113 # return a valid __bases__, and it's okay for it to be a normal -- 0114 # unrelated by inheritance -- class. 0115 def test_dont_mask_non_attribute_error_in_cls_arg(self): 0116 class B: pass 0117 0118 class C(object): 0119 def getbases(self): 0120 raise RuntimeError 0121 __bases__ = property(getbases) 0122 0123 self.assertRaises(RuntimeError, issubclass, B, C()) 0124 0125 def test_mask_attribute_error_in_cls_arg(self): 0126 class B: pass 0127 0128 class C(object): 0129 def getbases(self): 0130 raise AttributeError 0131 __bases__ = property(getbases) 0132 0133 self.assertRaises(TypeError, issubclass, B, C()) 0134 0135 0136 0137 # meta classes for creating abstract classes and instances 0138 class AbstractClass(object): 0139 def __init__(self, bases): 0140 self.bases = bases 0141 0142 def getbases(self): 0143 return self.bases 0144 __bases__ = property(getbases) 0145 0146 def __call__(self): 0147 return AbstractInstance(self) 0148 0149 class AbstractInstance(object): 0150 def __init__(self, klass): 0151 self.klass = klass 0152 0153 def getclass(self): 0154 return self.klass 0155 __class__ = property(getclass) 0156 0157 # abstract classes 0158 AbstractSuper = AbstractClass(bases=()) 0159 0160 AbstractChild = AbstractClass(bases=(AbstractSuper,)) 0161 0162 # normal classes 0163 class Super: 0164 pass 0165 0166 class Child(Super): 0167 pass 0168 0169 # new-style classes 0170 class NewSuper(object): 0171 pass 0172 0173 class NewChild(NewSuper): 0174 pass 0175 0176 0177 0178 class TestIsInstanceIsSubclass(unittest.TestCase): 0179 # Tests to ensure that isinstance and issubclass work on abstract 0180 # classes and instances. Before the 2.2 release, TypeErrors were 0181 # raised when boolean values should have been returned. The bug was 0182 # triggered by mixing 'normal' classes and instances were with 0183 # 'abstract' classes and instances. This case tries to test all 0184 # combinations. 0185 0186 def test_isinstance_normal(self): 0187 # normal instances 0188 self.assertEqual(True, isinstance(Super(), Super)) 0189 self.assertEqual(False, isinstance(Super(), Child)) 0190 self.assertEqual(False, isinstance(Super(), AbstractSuper)) 0191 self.assertEqual(False, isinstance(Super(), AbstractChild)) 0192 0193 self.assertEqual(True, isinstance(Child(), Super)) 0194 self.assertEqual(False, isinstance(Child(), AbstractSuper)) 0195 0196 def test_isinstance_abstract(self): 0197 # abstract instances 0198 self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper)) 0199 self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild)) 0200 self.assertEqual(False, isinstance(AbstractSuper(), Super)) 0201 self.assertEqual(False, isinstance(AbstractSuper(), Child)) 0202 0203 self.assertEqual(True, isinstance(AbstractChild(), AbstractChild)) 0204 self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper)) 0205 self.assertEqual(False, isinstance(AbstractChild(), Super)) 0206 self.assertEqual(False, isinstance(AbstractChild(), Child)) 0207 0208 def test_subclass_normal(self): 0209 # normal classes 0210 self.assertEqual(True, issubclass(Super, Super)) 0211 self.assertEqual(False, issubclass(Super, AbstractSuper)) 0212 self.assertEqual(False, issubclass(Super, Child)) 0213 0214 self.assertEqual(True, issubclass(Child, Child)) 0215 self.assertEqual(True, issubclass(Child, Super)) 0216 self.assertEqual(False, issubclass(Child, AbstractSuper)) 0217 0218 def test_subclass_abstract(self): 0219 # abstract classes 0220 self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper)) 0221 self.assertEqual(False, issubclass(AbstractSuper, AbstractChild)) 0222 self.assertEqual(False, issubclass(AbstractSuper, Child)) 0223 0224 self.assertEqual(True, issubclass(AbstractChild, AbstractChild)) 0225 self.assertEqual(True, issubclass(AbstractChild, AbstractSuper)) 0226 self.assertEqual(False, issubclass(AbstractChild, Super)) 0227 self.assertEqual(False, issubclass(AbstractChild, Child)) 0228 0229 def test_subclass_tuple(self): 0230 # test with a tuple as the second argument classes 0231 self.assertEqual(True, issubclass(Child, (Child,))) 0232 self.assertEqual(True, issubclass(Child, (Super,))) 0233 self.assertEqual(False, issubclass(Super, (Child,))) 0234 self.assertEqual(True, issubclass(Super, (Child, Super))) 0235 self.assertEqual(False, issubclass(Child, ())) 0236 self.assertEqual(True, issubclass(Super, (Child, (Super,)))) 0237 0238 self.assertEqual(True, issubclass(NewChild, (NewChild,))) 0239 self.assertEqual(True, issubclass(NewChild, (NewSuper,))) 0240 self.assertEqual(False, issubclass(NewSuper, (NewChild,))) 0241 self.assertEqual(True, issubclass(NewSuper, (NewChild, NewSuper))) 0242 self.assertEqual(False, issubclass(NewChild, ())) 0243 self.assertEqual(True, issubclass(NewSuper, (NewChild, (NewSuper,)))) 0244 0245 self.assertEqual(True, issubclass(int, (long, (float, int)))) 0246 self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring)))) 0247 0248 def test_subclass_recursion_limit(self): 0249 # make sure that issubclass raises RuntimeError before the C stack is 0250 # blown 0251 self.assertRaises(RuntimeError, blowstack, issubclass, str, str) 0252 0253 def test_isinstance_recursion_limit(self): 0254 # make sure that issubclass raises RuntimeError before the C stack is 0255 # blown 0256 self.assertRaises(RuntimeError, blowstack, isinstance, '', str) 0257 0258 def blowstack(fxn, arg, compare_to): 0259 # Make sure that calling isinstance with a deeply nested tuple for its 0260 # argument will raise RuntimeError eventually. 0261 tuple_arg = (compare_to,) 0262 for cnt in xrange(sys.getrecursionlimit()+5): 0263 tuple_arg = (tuple_arg,) 0264 fxn(arg, tuple_arg) 0265 0266 0267 def test_main(): 0268 test_support.run_unittest( 0269 TestIsInstanceExceptions, 0270 TestIsSubclassExceptions, 0271 TestIsInstanceIsSubclass 0272 ) 0273 0274 0275 if __name__ == '__main__': 0276 test_main() 0277
Generated by PyXR 0.9.4