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 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
# - cls isn't a a type, or a tuple
19
# - cls has a __bases__ attribute
20
# - inst has a __class__ attribute
21
# - inst.__class__ as no __bases__ attribute
23
# Sounds complicated, I know, but this mimics a situation where an
24
# extension type raises an AttributeError when its __bases__ attribute is
25
# gotten. In that case, isinstance() should return False.
26
def test_class_has_no_bases(self):
29
# This must return an object that has no __bases__ attribute
31
__class__ = property(getclass)
36
__bases__ = property(getbases)
38
self.assertEqual(False, isinstance(I(), C()))
40
# Like above except that inst.__class__.__bases__ raises an exception
41
# other than AttributeError
42
def test_bases_raises_other_than_attribute_error(self):
46
__bases__ = property(getbases)
51
__class__ = property(getclass)
56
__bases__ = property(getbases)
58
self.assertRaises(RuntimeError, isinstance, I(), C())
60
# Here's a situation where getattr(cls, '__bases__') raises an exception.
61
# If that exception is not AttributeError, it should not get masked
62
def test_dont_mask_non_attribute_error(self):
68
__bases__ = property(getbases)
70
self.assertRaises(RuntimeError, isinstance, I(), C())
72
# Like above, except that getattr(cls, '__bases__') raises an
73
# AttributeError, which /should/ get masked as a TypeError
74
def test_mask_attribute_error(self):
80
__bases__ = property(getbases)
82
self.assertRaises(TypeError, isinstance, I(), C())
86
# These tests are similar to above, but tickle certain code paths in
87
# issubclass() instead of isinstance() -- really PyObject_IsSubclass()
88
# vs. PyObject_IsInstance().
89
class TestIsSubclassExceptions(unittest.TestCase):
90
def test_dont_mask_non_attribute_error(self):
94
__bases__ = property(getbases)
98
self.assertRaises(RuntimeError, issubclass, C(), S())
100
def test_mask_attribute_error(self):
104
__bases__ = property(getbases)
108
self.assertRaises(TypeError, issubclass, C(), S())
110
# Like above, but test the second branch, where the __bases__ of the
111
# second arg (the cls arg) is tested. This means the first arg must
112
# return a valid __bases__, and it's okay for it to be a normal --
113
# unrelated by inheritance -- class.
114
def test_dont_mask_non_attribute_error_in_cls_arg(self):
120
__bases__ = property(getbases)
122
self.assertRaises(RuntimeError, issubclass, B, C())
124
def test_mask_attribute_error_in_cls_arg(self):
130
__bases__ = property(getbases)
132
self.assertRaises(TypeError, issubclass, B, C())
136
# meta classes for creating abstract classes and instances
137
class AbstractClass(object):
138
def __init__(self, bases):
143
__bases__ = property(getbases)
146
return AbstractInstance(self)
148
class AbstractInstance(object):
149
def __init__(self, klass):
154
__class__ = property(getclass)
157
AbstractSuper = AbstractClass(bases=())
159
AbstractChild = AbstractClass(bases=(AbstractSuper,))
169
class NewSuper(object):
172
class NewChild(NewSuper):
177
class TestIsInstanceIsSubclass(unittest.TestCase):
178
# Tests to ensure that isinstance and issubclass work on abstract
179
# classes and instances. Before the 2.2 release, TypeErrors were
180
# raised when boolean values should have been returned. The bug was
181
# triggered by mixing 'normal' classes and instances were with
182
# 'abstract' classes and instances. This case tries to test all
185
def test_isinstance_normal(self):
187
self.assertEqual(True, isinstance(Super(), Super))
188
self.assertEqual(False, isinstance(Super(), Child))
189
self.assertEqual(False, isinstance(Super(), AbstractSuper))
190
self.assertEqual(False, isinstance(Super(), AbstractChild))
192
self.assertEqual(True, isinstance(Child(), Super))
193
self.assertEqual(False, isinstance(Child(), AbstractSuper))
195
def test_isinstance_abstract(self):
197
self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper))
198
self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild))
199
self.assertEqual(False, isinstance(AbstractSuper(), Super))
200
self.assertEqual(False, isinstance(AbstractSuper(), Child))
202
self.assertEqual(True, isinstance(AbstractChild(), AbstractChild))
203
self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper))
204
self.assertEqual(False, isinstance(AbstractChild(), Super))
205
self.assertEqual(False, isinstance(AbstractChild(), Child))
207
def test_subclass_normal(self):
209
self.assertEqual(True, issubclass(Super, Super))
210
self.assertEqual(False, issubclass(Super, AbstractSuper))
211
self.assertEqual(False, issubclass(Super, Child))
213
self.assertEqual(True, issubclass(Child, Child))
214
self.assertEqual(True, issubclass(Child, Super))
215
self.assertEqual(False, issubclass(Child, AbstractSuper))
217
def test_subclass_abstract(self):
219
self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper))
220
self.assertEqual(False, issubclass(AbstractSuper, AbstractChild))
221
self.assertEqual(False, issubclass(AbstractSuper, Child))
223
self.assertEqual(True, issubclass(AbstractChild, AbstractChild))
224
self.assertEqual(True, issubclass(AbstractChild, AbstractSuper))
225
self.assertEqual(False, issubclass(AbstractChild, Super))
226
self.assertEqual(False, issubclass(AbstractChild, Child))
228
def test_subclass_tuple(self):
229
# test with a tuple as the second argument classes
230
self.assertEqual(True, issubclass(Child, (Child,)))
231
self.assertEqual(True, issubclass(Child, (Super,)))
232
self.assertEqual(False, issubclass(Super, (Child,)))
233
self.assertEqual(True, issubclass(Super, (Child, Super)))
234
self.assertEqual(False, issubclass(Child, ()))
235
self.assertEqual(True, issubclass(Super, (Child, (Super,))))
237
self.assertEqual(True, issubclass(NewChild, (NewChild,)))
238
self.assertEqual(True, issubclass(NewChild, (NewSuper,)))
239
self.assertEqual(False, issubclass(NewSuper, (NewChild,)))
240
self.assertEqual(True, issubclass(NewSuper, (NewChild, NewSuper)))
241
self.assertEqual(False, issubclass(NewChild, ()))
242
self.assertEqual(True, issubclass(NewSuper, (NewChild, (NewSuper,))))
244
self.assertEqual(True, issubclass(int, (int, (float, int))))
245
self.assertEqual(True, issubclass(str, (str, (Child, NewChild, str))))
247
def test_subclass_recursion_limit(self):
248
# make sure that issubclass raises RuntimeError before the C stack is
250
self.assertRaises(RuntimeError, blowstack, issubclass, str, str)
252
def test_isinstance_recursion_limit(self):
253
# make sure that issubclass raises RuntimeError before the C stack is
255
self.assertRaises(RuntimeError, blowstack, isinstance, '', str)
257
def blowstack(fxn, arg, compare_to):
258
# Make sure that calling isinstance with a deeply nested tuple for its
259
# argument will raise RuntimeError eventually.
260
tuple_arg = (compare_to,)
261
for cnt in range(sys.getrecursionlimit()+5):
262
tuple_arg = (tuple_arg,)
267
support.run_unittest(
268
TestIsInstanceExceptions,
269
TestIsSubclassExceptions,
270
TestIsInstanceIsSubclass
274
if __name__ == '__main__':