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.
6 from test
import test_support
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
):
30 # This must return an object that has no __bases__ attribute
32 __class__
= property(getclass
)
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
):
47 __bases__
= property(getbases
)
52 __class__
= property(getclass
)
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
):
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
):
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
):
95 __bases__
= property(getbases
)
99 self
.assertRaises(RuntimeError, issubclass, C(), S())
101 def test_mask_attribute_error(self
):
105 __bases__
= property(getbases
)
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
):
121 __bases__
= property(getbases
)
123 self
.assertRaises(RuntimeError, issubclass, B
, C())
125 def test_mask_attribute_error_in_cls_arg(self
):
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
):
144 __bases__
= property(getbases
)
147 return AbstractInstance(self
)
149 class AbstractInstance(object):
150 def __init__(self
, klass
):
155 __class__
= property(getclass
)
158 AbstractSuper
= AbstractClass(bases
=())
160 AbstractChild
= AbstractClass(bases
=(AbstractSuper
,))
170 class NewSuper(object):
173 class NewChild(NewSuper
):
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
186 def test_isinstance_normal(self
):
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
):
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
):
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
):
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
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
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
,)
269 test_support
.run_unittest(
270 TestIsInstanceExceptions
,
271 TestIsSubclassExceptions
,
272 TestIsInstanceIsSubclass
276 if __name__
== '__main__':