Issue #6615: logging: Used weak references in internal handler list. Thanks to flox...
[python.git] / Lib / test / test_isinstance.py
blob25b0816713bba1d17922bbe627f326ad70a3aa89
1 # Tests some corner cases with isinstance() and issubclass(). While these
2 # tests use new style classes and properties, they actually do whitebox
3 # testing of error conditions uncovered when using extension types.
5 import unittest
6 from test import test_support
7 import sys
11 class TestIsInstanceExceptions(unittest.TestCase):
12 # Test to make sure that an AttributeError when accessing the instance's
13 # class's bases is masked. This was actually a bug in Python 2.2 and
14 # 2.2.1 where the exception wasn't caught but it also wasn't being cleared
15 # (leading to an "undetected error" in the debug build). Set up is,
16 # isinstance(inst, cls) where:
18 # - inst isn't an InstanceType
19 # - cls isn't a ClassType, a TypeType, or a TupleType
20 # - cls has a __bases__ attribute
21 # - inst has a __class__ attribute
22 # - inst.__class__ as no __bases__ attribute
24 # Sounds complicated, I know, but this mimics a situation where an
25 # extension type raises an AttributeError when its __bases__ attribute is
26 # gotten. In that case, isinstance() should return False.
27 def test_class_has_no_bases(self):
28 class I(object):
29 def getclass(self):
30 # This must return an object that has no __bases__ attribute
31 return None
32 __class__ = property(getclass)
34 class C(object):
35 def getbases(self):
36 return ()
37 __bases__ = property(getbases)
39 self.assertEqual(False, isinstance(I(), C()))
41 # Like above except that inst.__class__.__bases__ raises an exception
42 # other than AttributeError
43 def test_bases_raises_other_than_attribute_error(self):
44 class E(object):
45 def getbases(self):
46 raise RuntimeError
47 __bases__ = property(getbases)
49 class I(object):
50 def getclass(self):
51 return E()
52 __class__ = property(getclass)
54 class C(object):
55 def getbases(self):
56 return ()
57 __bases__ = property(getbases)
59 self.assertRaises(RuntimeError, isinstance, I(), C())
61 # Here's a situation where getattr(cls, '__bases__') raises an exception.
62 # If that exception is not AttributeError, it should not get masked
63 def test_dont_mask_non_attribute_error(self):
64 class I: pass
66 class C(object):
67 def getbases(self):
68 raise RuntimeError
69 __bases__ = property(getbases)
71 self.assertRaises(RuntimeError, isinstance, I(), C())
73 # Like above, except that getattr(cls, '__bases__') raises an
74 # AttributeError, which /should/ get masked as a TypeError
75 def test_mask_attribute_error(self):
76 class I: pass
78 class C(object):
79 def getbases(self):
80 raise AttributeError
81 __bases__ = property(getbases)
83 self.assertRaises(TypeError, isinstance, I(), C())
87 # These tests are similar to above, but tickle certain code paths in
88 # issubclass() instead of isinstance() -- really PyObject_IsSubclass()
89 # vs. PyObject_IsInstance().
90 class TestIsSubclassExceptions(unittest.TestCase):
91 def test_dont_mask_non_attribute_error(self):
92 class C(object):
93 def getbases(self):
94 raise RuntimeError
95 __bases__ = property(getbases)
97 class S(C): pass
99 self.assertRaises(RuntimeError, issubclass, C(), S())
101 def test_mask_attribute_error(self):
102 class C(object):
103 def getbases(self):
104 raise AttributeError
105 __bases__ = property(getbases)
107 class S(C): pass
109 self.assertRaises(TypeError, issubclass, C(), S())
111 # Like above, but test the second branch, where the __bases__ of the
112 # second arg (the cls arg) is tested. This means the first arg must
113 # return a valid __bases__, and it's okay for it to be a normal --
114 # unrelated by inheritance -- class.
115 def test_dont_mask_non_attribute_error_in_cls_arg(self):
116 class B: pass
118 class C(object):
119 def getbases(self):
120 raise RuntimeError
121 __bases__ = property(getbases)
123 self.assertRaises(RuntimeError, issubclass, B, C())
125 def test_mask_attribute_error_in_cls_arg(self):
126 class B: pass
128 class C(object):
129 def getbases(self):
130 raise AttributeError
131 __bases__ = property(getbases)
133 self.assertRaises(TypeError, issubclass, B, C())
137 # meta classes for creating abstract classes and instances
138 class AbstractClass(object):
139 def __init__(self, bases):
140 self.bases = bases
142 def getbases(self):
143 return self.bases
144 __bases__ = property(getbases)
146 def __call__(self):
147 return AbstractInstance(self)
149 class AbstractInstance(object):
150 def __init__(self, klass):
151 self.klass = klass
153 def getclass(self):
154 return self.klass
155 __class__ = property(getclass)
157 # abstract classes
158 AbstractSuper = AbstractClass(bases=())
160 AbstractChild = AbstractClass(bases=(AbstractSuper,))
162 # normal classes
163 class Super:
164 pass
166 class Child(Super):
167 pass
169 # new-style classes
170 class NewSuper(object):
171 pass
173 class NewChild(NewSuper):
174 pass
178 class TestIsInstanceIsSubclass(unittest.TestCase):
179 # Tests to ensure that isinstance and issubclass work on abstract
180 # classes and instances. Before the 2.2 release, TypeErrors were
181 # raised when boolean values should have been returned. The bug was
182 # triggered by mixing 'normal' classes and instances were with
183 # 'abstract' classes and instances. This case tries to test all
184 # combinations.
186 def test_isinstance_normal(self):
187 # normal instances
188 self.assertEqual(True, isinstance(Super(), Super))
189 self.assertEqual(False, isinstance(Super(), Child))
190 self.assertEqual(False, isinstance(Super(), AbstractSuper))
191 self.assertEqual(False, isinstance(Super(), AbstractChild))
193 self.assertEqual(True, isinstance(Child(), Super))
194 self.assertEqual(False, isinstance(Child(), AbstractSuper))
196 def test_isinstance_abstract(self):
197 # abstract instances
198 self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper))
199 self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild))
200 self.assertEqual(False, isinstance(AbstractSuper(), Super))
201 self.assertEqual(False, isinstance(AbstractSuper(), Child))
203 self.assertEqual(True, isinstance(AbstractChild(), AbstractChild))
204 self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper))
205 self.assertEqual(False, isinstance(AbstractChild(), Super))
206 self.assertEqual(False, isinstance(AbstractChild(), Child))
208 def test_subclass_normal(self):
209 # normal classes
210 self.assertEqual(True, issubclass(Super, Super))
211 self.assertEqual(False, issubclass(Super, AbstractSuper))
212 self.assertEqual(False, issubclass(Super, Child))
214 self.assertEqual(True, issubclass(Child, Child))
215 self.assertEqual(True, issubclass(Child, Super))
216 self.assertEqual(False, issubclass(Child, AbstractSuper))
218 def test_subclass_abstract(self):
219 # abstract classes
220 self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper))
221 self.assertEqual(False, issubclass(AbstractSuper, AbstractChild))
222 self.assertEqual(False, issubclass(AbstractSuper, Child))
224 self.assertEqual(True, issubclass(AbstractChild, AbstractChild))
225 self.assertEqual(True, issubclass(AbstractChild, AbstractSuper))
226 self.assertEqual(False, issubclass(AbstractChild, Super))
227 self.assertEqual(False, issubclass(AbstractChild, Child))
229 def test_subclass_tuple(self):
230 # test with a tuple as the second argument classes
231 self.assertEqual(True, issubclass(Child, (Child,)))
232 self.assertEqual(True, issubclass(Child, (Super,)))
233 self.assertEqual(False, issubclass(Super, (Child,)))
234 self.assertEqual(True, issubclass(Super, (Child, Super)))
235 self.assertEqual(False, issubclass(Child, ()))
236 self.assertEqual(True, issubclass(Super, (Child, (Super,))))
238 self.assertEqual(True, issubclass(NewChild, (NewChild,)))
239 self.assertEqual(True, issubclass(NewChild, (NewSuper,)))
240 self.assertEqual(False, issubclass(NewSuper, (NewChild,)))
241 self.assertEqual(True, issubclass(NewSuper, (NewChild, NewSuper)))
242 self.assertEqual(False, issubclass(NewChild, ()))
243 self.assertEqual(True, issubclass(NewSuper, (NewChild, (NewSuper,))))
245 self.assertEqual(True, issubclass(int, (long, (float, int))))
246 if test_support.have_unicode:
247 self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring))))
249 def test_subclass_recursion_limit(self):
250 # make sure that issubclass raises RuntimeError before the C stack is
251 # blown
252 self.assertRaises(RuntimeError, blowstack, issubclass, str, str)
254 def test_isinstance_recursion_limit(self):
255 # make sure that issubclass raises RuntimeError before the C stack is
256 # blown
257 self.assertRaises(RuntimeError, blowstack, isinstance, '', str)
259 def blowstack(fxn, arg, compare_to):
260 # Make sure that calling isinstance with a deeply nested tuple for its
261 # argument will raise RuntimeError eventually.
262 tuple_arg = (compare_to,)
263 for cnt in xrange(sys.getrecursionlimit()+5):
264 tuple_arg = (tuple_arg,)
265 fxn(arg, tuple_arg)
268 def test_main():
269 test_support.run_unittest(
270 TestIsInstanceExceptions,
271 TestIsSubclassExceptions,
272 TestIsInstanceIsSubclass
276 if __name__ == '__main__':
277 test_main()