~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/test/test_isinstance.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
4
 
 
5
import unittest
 
6
from test import support
 
7
import sys
 
8
 
 
9
 
 
10
 
 
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:
 
17
    #
 
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
 
22
    #
 
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):
 
27
        class I(object):
 
28
            def getclass(self):
 
29
                # This must return an object that has no __bases__ attribute
 
30
                return None
 
31
            __class__ = property(getclass)
 
32
 
 
33
        class C(object):
 
34
            def getbases(self):
 
35
                return ()
 
36
            __bases__ = property(getbases)
 
37
 
 
38
        self.assertEqual(False, isinstance(I(), C()))
 
39
 
 
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):
 
43
        class E(object):
 
44
            def getbases(self):
 
45
                raise RuntimeError
 
46
            __bases__ = property(getbases)
 
47
 
 
48
        class I(object):
 
49
            def getclass(self):
 
50
                return E()
 
51
            __class__ = property(getclass)
 
52
 
 
53
        class C(object):
 
54
            def getbases(self):
 
55
                return ()
 
56
            __bases__ = property(getbases)
 
57
 
 
58
        self.assertRaises(RuntimeError, isinstance, I(), C())
 
59
 
 
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):
 
63
        class I: pass
 
64
 
 
65
        class C(object):
 
66
            def getbases(self):
 
67
                raise RuntimeError
 
68
            __bases__ = property(getbases)
 
69
 
 
70
        self.assertRaises(RuntimeError, isinstance, I(), C())
 
71
 
 
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):
 
75
        class I: pass
 
76
 
 
77
        class C(object):
 
78
            def getbases(self):
 
79
                raise AttributeError
 
80
            __bases__ = property(getbases)
 
81
 
 
82
        self.assertRaises(TypeError, isinstance, I(), C())
 
83
 
 
84
 
 
85
 
 
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):
 
91
        class C(object):
 
92
            def getbases(self):
 
93
                raise RuntimeError
 
94
            __bases__ = property(getbases)
 
95
 
 
96
        class S(C): pass
 
97
 
 
98
        self.assertRaises(RuntimeError, issubclass, C(), S())
 
99
 
 
100
    def test_mask_attribute_error(self):
 
101
        class C(object):
 
102
            def getbases(self):
 
103
                raise AttributeError
 
104
            __bases__ = property(getbases)
 
105
 
 
106
        class S(C): pass
 
107
 
 
108
        self.assertRaises(TypeError, issubclass, C(), S())
 
109
 
 
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):
 
115
        class B: pass
 
116
 
 
117
        class C(object):
 
118
            def getbases(self):
 
119
                raise RuntimeError
 
120
            __bases__ = property(getbases)
 
121
 
 
122
        self.assertRaises(RuntimeError, issubclass, B, C())
 
123
 
 
124
    def test_mask_attribute_error_in_cls_arg(self):
 
125
        class B: pass
 
126
 
 
127
        class C(object):
 
128
            def getbases(self):
 
129
                raise AttributeError
 
130
            __bases__ = property(getbases)
 
131
 
 
132
        self.assertRaises(TypeError, issubclass, B, C())
 
133
 
 
134
 
 
135
 
 
136
# meta classes for creating abstract classes and instances
 
137
class AbstractClass(object):
 
138
    def __init__(self, bases):
 
139
        self.bases = bases
 
140
 
 
141
    def getbases(self):
 
142
        return self.bases
 
143
    __bases__ = property(getbases)
 
144
 
 
145
    def __call__(self):
 
146
        return AbstractInstance(self)
 
147
 
 
148
class AbstractInstance(object):
 
149
    def __init__(self, klass):
 
150
        self.klass = klass
 
151
 
 
152
    def getclass(self):
 
153
        return self.klass
 
154
    __class__ = property(getclass)
 
155
 
 
156
# abstract classes
 
157
AbstractSuper = AbstractClass(bases=())
 
158
 
 
159
AbstractChild = AbstractClass(bases=(AbstractSuper,))
 
160
 
 
161
# normal classes
 
162
class Super:
 
163
    pass
 
164
 
 
165
class Child(Super):
 
166
    pass
 
167
 
 
168
# new-style classes
 
169
class NewSuper(object):
 
170
    pass
 
171
 
 
172
class NewChild(NewSuper):
 
173
    pass
 
174
 
 
175
 
 
176
 
 
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
 
183
    # combinations.
 
184
 
 
185
    def test_isinstance_normal(self):
 
186
        # normal instances
 
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))
 
191
 
 
192
        self.assertEqual(True, isinstance(Child(), Super))
 
193
        self.assertEqual(False, isinstance(Child(), AbstractSuper))
 
194
 
 
195
    def test_isinstance_abstract(self):
 
196
        # abstract instances
 
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))
 
201
 
 
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))
 
206
 
 
207
    def test_subclass_normal(self):
 
208
        # normal classes
 
209
        self.assertEqual(True, issubclass(Super, Super))
 
210
        self.assertEqual(False, issubclass(Super, AbstractSuper))
 
211
        self.assertEqual(False, issubclass(Super, Child))
 
212
 
 
213
        self.assertEqual(True, issubclass(Child, Child))
 
214
        self.assertEqual(True, issubclass(Child, Super))
 
215
        self.assertEqual(False, issubclass(Child, AbstractSuper))
 
216
 
 
217
    def test_subclass_abstract(self):
 
218
        # abstract classes
 
219
        self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper))
 
220
        self.assertEqual(False, issubclass(AbstractSuper, AbstractChild))
 
221
        self.assertEqual(False, issubclass(AbstractSuper, Child))
 
222
 
 
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))
 
227
 
 
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,))))
 
236
 
 
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,))))
 
243
 
 
244
        self.assertEqual(True, issubclass(int, (int, (float, int))))
 
245
        self.assertEqual(True, issubclass(str, (str, (Child, NewChild, str))))
 
246
 
 
247
    def test_subclass_recursion_limit(self):
 
248
        # make sure that issubclass raises RuntimeError before the C stack is
 
249
        # blown
 
250
        self.assertRaises(RuntimeError, blowstack, issubclass, str, str)
 
251
 
 
252
    def test_isinstance_recursion_limit(self):
 
253
        # make sure that issubclass raises RuntimeError before the C stack is
 
254
        # blown
 
255
        self.assertRaises(RuntimeError, blowstack, isinstance, '', str)
 
256
 
 
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,)
 
263
        fxn(arg, tuple_arg)
 
264
 
 
265
 
 
266
def test_main():
 
267
    support.run_unittest(
 
268
        TestIsInstanceExceptions,
 
269
        TestIsSubclassExceptions,
 
270
        TestIsInstanceIsSubclass
 
271
    )
 
272
 
 
273
 
 
274
if __name__ == '__main__':
 
275
    test_main()