PyXR

c:\python24\lib \ test \ test_isinstance.py



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
SourceForge.net Logo