PageRenderTime 46ms CodeModel.GetById 2ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 1ms

/Lib/test/test_exceptions.py

http://unladen-swallow.googlecode.com/
Python | 507 lines | 426 code | 56 blank | 25 comment | 21 complexity | 15711cf1e65fdc03e0875ed71d20617c MD5 | raw file
  1# Python test set -- part 5, built-in exceptions
  2
  3import os
  4import sys
  5import unittest
  6import pickle, cPickle
  7import warnings
  8
  9from test.test_support import TESTFN, unlink, run_unittest, captured_output
 10from test.test_pep352 import ignore_message_warning
 11
 12# XXX This is not really enough, each *operation* should be tested!
 13
 14class ExceptionTests(unittest.TestCase):
 15
 16    def testReload(self):
 17        # Reloading the built-in exceptions module failed prior to Py2.2, while it
 18        # should act the same as reloading built-in sys.
 19        try:
 20            import exceptions
 21            reload(exceptions)
 22        except ImportError, e:
 23            self.fail("reloading exceptions: %s" % e)
 24
 25    def raise_catch(self, exc, excname):
 26        try:
 27            raise exc, "spam"
 28        except exc, err:
 29            buf1 = str(err)
 30        try:
 31            raise exc("spam")
 32        except exc, err:
 33            buf2 = str(err)
 34        self.assertEquals(buf1, buf2)
 35        self.assertEquals(exc.__name__, excname)
 36
 37    def testRaising(self):
 38        self.raise_catch(AttributeError, "AttributeError")
 39        self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")
 40
 41        self.raise_catch(EOFError, "EOFError")
 42        fp = open(TESTFN, 'w')
 43        fp.close()
 44        fp = open(TESTFN, 'r')
 45        savestdin = sys.stdin
 46        try:
 47            try:
 48                sys.stdin = fp
 49                x = raw_input()
 50            except EOFError:
 51                pass
 52        finally:
 53            sys.stdin = savestdin
 54            fp.close()
 55            unlink(TESTFN)
 56
 57        self.raise_catch(IOError, "IOError")
 58        self.assertRaises(IOError, open, 'this file does not exist', 'r')
 59
 60        self.raise_catch(ImportError, "ImportError")
 61        self.assertRaises(ImportError, __import__, "undefined_module")
 62
 63        self.raise_catch(IndexError, "IndexError")
 64        x = []
 65        self.assertRaises(IndexError, x.__getitem__, 10)
 66
 67        self.raise_catch(KeyError, "KeyError")
 68        x = {}
 69        self.assertRaises(KeyError, x.__getitem__, 'key')
 70
 71        self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")
 72
 73        self.raise_catch(MemoryError, "MemoryError")
 74
 75        self.raise_catch(NameError, "NameError")
 76        try: x = undefined_variable
 77        except NameError: pass
 78
 79        self.raise_catch(OverflowError, "OverflowError")
 80        x = 1
 81        for dummy in range(128):
 82            x += x  # this simply shouldn't blow up
 83
 84        self.raise_catch(RuntimeError, "RuntimeError")
 85
 86        self.raise_catch(SyntaxError, "SyntaxError")
 87        try: exec '/\n'
 88        except SyntaxError: pass
 89
 90        self.raise_catch(IndentationError, "IndentationError")
 91
 92        self.raise_catch(TabError, "TabError")
 93        # can only be tested under -tt, and is the only test for -tt
 94        #try: compile("try:\n\t1/0\n    \t1/0\nfinally:\n pass\n", '<string>', 'exec')
 95        #except TabError: pass
 96        #else: self.fail("TabError not raised")
 97
 98        self.raise_catch(SystemError, "SystemError")
 99
100        self.raise_catch(SystemExit, "SystemExit")
101        self.assertRaises(SystemExit, sys.exit, 0)
102
103        self.raise_catch(TypeError, "TypeError")
104        try: [] + ()
105        except TypeError: pass
106
107        self.raise_catch(ValueError, "ValueError")
108        self.assertRaises(ValueError, chr, 10000)
109
110        self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
111        try: x = 1/0
112        except ZeroDivisionError: pass
113
114        self.raise_catch(Exception, "Exception")
115        try: x = 1/0
116        except Exception, e: pass
117
118    def testExcInfoUnaffectedByNestedFunction(self):
119        def raise_and_catch():
120            try:
121                raise IndexError("inner exception")
122            except IndexError:
123                pass
124        try:
125            raise ValueError("outer exception")
126        except ValueError:
127            exc, val, tb = sys.exc_info()
128            self.assertEquals(exc, ValueError)
129            self.assertEquals(val.args, ("outer exception",))
130            raise_and_catch()  # Risk clobbering sys.exc_info().
131            self.assertEquals(sys.exc_info(), (exc, val, tb))
132
133    def testExcInfoUnaffectedByGenerator(self):
134        def raising_generator():
135            try:
136                raise IndexError("inner exception")
137            except IndexError:
138                yield 3
139
140        try:
141            raise ValueError("outer exception")
142        except ValueError:
143            exc, val, tb = sys.exc_info()
144            self.assertEquals(exc, ValueError)
145            self.assertEquals(val.args, ("outer exception",))
146            g = raising_generator()
147            self.assertEquals(g.next(), 3)  # Risk clobbering sys.exc_info().
148            self.assertEquals(sys.exc_info(), (exc, val, tb))
149            self.assertRaises(StopIteration, g.next)
150            self.assertEquals(sys.exc_info(), (exc, val, tb))
151
152    def testExcInfoInGeneratorClobberedByYield(self):
153        def raising_generator():
154            try:
155                raise IndexError("inner exception")
156            except IndexError:
157                exc, val, tb = sys.exc_info()
158                self.assertEquals(exc, IndexError)
159                self.assertEquals(val.args, ("inner exception",))
160                yield 3
161                # The next line ought to be the assertion, but
162                # Python 2.6 resets the exception from the calling
163                # function, so we test bug-for-bug compatibility
164                # within the 2.6 series.
165                #
166                # self.assertEquals(sys.exc_info(), (exc, val, tb))
167                self.assertEquals(sys.exc_info(), (None, None, None))
168
169        for i in raising_generator():
170            pass
171
172    def testExcInfoVisibleInNestedFunction(self):
173        def check_exc_info(exc, val, tb):
174            self.assertEquals(sys.exc_info(), (exc, val, tb))
175            try:
176                raise IndexError("inner exception")
177            except IndexError:
178                pass
179            exc3, val3, tb3 = sys.exc_info()
180            self.assertEquals(exc3, IndexError)
181            self.assertEquals(val3.args, ("inner exception",))
182            self.assertNotEquals(tb3, tb)
183
184        try:
185            raise ValueError("outer exception")
186        except ValueError:
187            check_exc_info(*sys.exc_info())
188
189    def testSyntaxErrorMessage(self):
190        # make sure the right exception message is raised for each of
191        # these code fragments
192
193        def ckmsg(src, msg):
194            try:
195                compile(src, '<fragment>', 'exec')
196            except SyntaxError, e:
197                if e.msg != msg:
198                    self.fail("expected %s, got %s" % (msg, e.msg))
199            else:
200                self.fail("failed to get expected SyntaxError")
201
202        s = '''while 1:
203            try:
204                pass
205            finally:
206                continue'''
207
208        if not sys.platform.startswith('java'):
209            ckmsg(s, "'continue' not supported inside 'finally' clause")
210
211        s = '''if 1:
212        try:
213            continue
214        except:
215            pass'''
216
217        ckmsg(s, "'continue' not properly in loop")
218        ckmsg("continue\n", "'continue' not properly in loop")
219
220    def testSettingException(self):
221        # test that setting an exception at the C level works even if the
222        # exception object can't be constructed.
223
224        class BadException:
225            def __init__(self_):
226                raise RuntimeError, "can't instantiate BadException"
227
228        def test_capi1():
229            import _testcapi
230            try:
231                _testcapi.raise_exception(BadException, 1)
232            except TypeError, err:
233                exc, err, tb = sys.exc_info()
234                co = tb.tb_frame.f_code
235                self.assertEquals(co.co_name, "test_capi1")
236                self.assert_(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
237            else:
238                self.fail("Expected exception")
239
240        def test_capi2():
241            import _testcapi
242            try:
243                _testcapi.raise_exception(BadException, 0)
244            except RuntimeError, err:
245                exc, err, tb = sys.exc_info()
246                co = tb.tb_frame.f_code
247                self.assertEquals(co.co_name, "__init__")
248                self.assert_(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
249                co2 = tb.tb_frame.f_back.f_code
250                self.assertEquals(co2.co_name, "test_capi2")
251            else:
252                self.fail("Expected exception")
253
254        if not sys.platform.startswith('java'):
255            test_capi1()
256            test_capi2()
257
258    def test_WindowsError(self):
259        try:
260            WindowsError
261        except NameError:
262            pass
263        else:
264            self.failUnlessEqual(str(WindowsError(1001)),
265                                 "1001")
266            self.failUnlessEqual(str(WindowsError(1001, "message")),
267                                 "[Error 1001] message")
268            self.failUnlessEqual(WindowsError(1001, "message").errno, 22)
269            self.failUnlessEqual(WindowsError(1001, "message").winerror, 1001)
270
271    def testAttributes(self):
272        # test that exception attributes are happy
273
274        exceptionList = [
275            (BaseException, (), {'message' : '', 'args' : ()}),
276            (BaseException, (1, ), {'message' : 1, 'args' : (1,)}),
277            (BaseException, ('foo',),
278                {'message' : 'foo', 'args' : ('foo',)}),
279            (BaseException, ('foo', 1),
280                {'message' : '', 'args' : ('foo', 1)}),
281            (SystemExit, ('foo',),
282                {'message' : 'foo', 'args' : ('foo',), 'code' : 'foo'}),
283            (IOError, ('foo',),
284                {'message' : 'foo', 'args' : ('foo',), 'filename' : None,
285                 'errno' : None, 'strerror' : None}),
286            (IOError, ('foo', 'bar'),
287                {'message' : '', 'args' : ('foo', 'bar'), 'filename' : None,
288                 'errno' : 'foo', 'strerror' : 'bar'}),
289            (IOError, ('foo', 'bar', 'baz'),
290                {'message' : '', 'args' : ('foo', 'bar'), 'filename' : 'baz',
291                 'errno' : 'foo', 'strerror' : 'bar'}),
292            (IOError, ('foo', 'bar', 'baz', 'quux'),
293                {'message' : '', 'args' : ('foo', 'bar', 'baz', 'quux')}),
294            (EnvironmentError, ('errnoStr', 'strErrorStr', 'filenameStr'),
295                {'message' : '', 'args' : ('errnoStr', 'strErrorStr'),
296                 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
297                 'filename' : 'filenameStr'}),
298            (EnvironmentError, (1, 'strErrorStr', 'filenameStr'),
299                {'message' : '', 'args' : (1, 'strErrorStr'), 'errno' : 1,
300                 'strerror' : 'strErrorStr', 'filename' : 'filenameStr'}),
301            (SyntaxError, (), {'message' : '', 'msg' : None, 'text' : None,
302                'filename' : None, 'lineno' : None, 'offset' : None,
303                'print_file_and_line' : None}),
304            (SyntaxError, ('msgStr',),
305                {'message' : 'msgStr', 'args' : ('msgStr',), 'text' : None,
306                 'print_file_and_line' : None, 'msg' : 'msgStr',
307                 'filename' : None, 'lineno' : None, 'offset' : None}),
308            (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
309                           'textStr')),
310                {'message' : '', 'offset' : 'offsetStr', 'text' : 'textStr',
311                 'args' : ('msgStr', ('filenameStr', 'linenoStr',
312                                      'offsetStr', 'textStr')),
313                 'print_file_and_line' : None, 'msg' : 'msgStr',
314                 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
315            (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
316                           'textStr', 'print_file_and_lineStr'),
317                {'message' : '', 'text' : None,
318                 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
319                           'textStr', 'print_file_and_lineStr'),
320                 'print_file_and_line' : None, 'msg' : 'msgStr',
321                 'filename' : None, 'lineno' : None, 'offset' : None}),
322            (UnicodeError, (), {'message' : '', 'args' : (),}),
323            (UnicodeEncodeError, ('ascii', u'a', 0, 1, 'ordinal not in range'),
324                {'message' : '', 'args' : ('ascii', u'a', 0, 1,
325                                           'ordinal not in range'),
326                 'encoding' : 'ascii', 'object' : u'a',
327                 'start' : 0, 'reason' : 'ordinal not in range'}),
328            (UnicodeDecodeError, ('ascii', '\xff', 0, 1, 'ordinal not in range'),
329                {'message' : '', 'args' : ('ascii', '\xff', 0, 1,
330                                           'ordinal not in range'),
331                 'encoding' : 'ascii', 'object' : '\xff',
332                 'start' : 0, 'reason' : 'ordinal not in range'}),
333            (UnicodeTranslateError, (u"\u3042", 0, 1, "ouch"),
334                {'message' : '', 'args' : (u'\u3042', 0, 1, 'ouch'),
335                 'object' : u'\u3042', 'reason' : 'ouch',
336                 'start' : 0, 'end' : 1}),
337        ]
338        try:
339            exceptionList.append(
340                (WindowsError, (1, 'strErrorStr', 'filenameStr'),
341                    {'message' : '', 'args' : (1, 'strErrorStr'),
342                     'strerror' : 'strErrorStr', 'winerror' : 1,
343                     'errno' : 22, 'filename' : 'filenameStr'})
344            )
345        except NameError:
346            pass
347
348        with warnings.catch_warnings():
349            ignore_message_warning()
350            for exc, args, expected in exceptionList:
351                try:
352                    raise exc(*args)
353                except BaseException, e:
354                    if type(e) is not exc:
355                        raise
356                    # Verify module name
357                    self.assertEquals(type(e).__module__, 'exceptions')
358                    # Verify no ref leaks in Exc_str()
359                    s = str(e)
360                    for checkArgName in expected:
361                        self.assertEquals(repr(getattr(e, checkArgName)),
362                                          repr(expected[checkArgName]),
363                                          'exception "%s", attribute "%s"' %
364                                           (repr(e), checkArgName))
365
366                    # test for pickling support
367                    for p in pickle, cPickle:
368                        for protocol in range(p.HIGHEST_PROTOCOL + 1):
369                            new = p.loads(p.dumps(e, protocol))
370                            for checkArgName in expected:
371                                got = repr(getattr(new, checkArgName))
372                                want = repr(expected[checkArgName])
373                                self.assertEquals(got, want,
374                                                  'pickled "%r", attribute "%s"' %
375                                                  (e, checkArgName))
376
377
378    def testDeprecatedMessageAttribute(self):
379        # Accessing BaseException.message and relying on its value set by
380        # BaseException.__init__ triggers a deprecation warning.
381        exc = BaseException("foo")
382        with warnings.catch_warnings(record=True) as w:
383            self.assertEquals(exc.message, "foo")
384        self.assertEquals(len(w), 1)
385        self.assertEquals(w[0].category, DeprecationWarning)
386        self.assertEquals(
387            str(w[0].message),
388            "BaseException.message has been deprecated as of Python 2.6")
389
390
391    def testRegularMessageAttribute(self):
392        # Accessing BaseException.message after explicitly setting a value
393        # for it does not trigger a deprecation warning.
394        exc = BaseException("foo")
395        exc.message = "bar"
396        with warnings.catch_warnings(record=True) as w:
397            self.assertEquals(exc.message, "bar")
398        self.assertEquals(len(w), 0)
399        # Deleting the message is supported, too.
400        del exc.message
401        self.assertRaises(AttributeError, getattr, exc, "message")
402
403    def testPickleMessageAttribute(self):
404        # Pickling with message attribute must work, as well.
405        e = Exception("foo")
406        f = Exception("foo")
407        f.message = "bar"
408        for p in pickle, cPickle:
409            ep = p.loads(p.dumps(e))
410            with warnings.catch_warnings():
411                ignore_message_warning()
412                self.assertEqual(ep.message, "foo")
413            fp = p.loads(p.dumps(f))
414            self.assertEqual(fp.message, "bar")
415
416    def testSlicing(self):
417        # Test that you can slice an exception directly instead of requiring
418        # going through the 'args' attribute.
419        args = (1, 2, 3)
420        exc = BaseException(*args)
421        self.failUnlessEqual(exc[:], args)
422
423    def testKeywordArgs(self):
424        # test that builtin exception don't take keyword args,
425        # but user-defined subclasses can if they want
426        self.assertRaises(TypeError, BaseException, a=1)
427
428        class DerivedException(BaseException):
429            def __init__(self, fancy_arg):
430                BaseException.__init__(self)
431                self.fancy_arg = fancy_arg
432
433        x = DerivedException(fancy_arg=42)
434        self.assertEquals(x.fancy_arg, 42)
435
436    def testInfiniteRecursion(self):
437        def f():
438            return f()
439        self.assertRaises(RuntimeError, f)
440
441        def g():
442            try:
443                return g()
444            except ValueError:
445                return -1
446
447        # The test prints an unraisable recursion error when
448        # doing "except ValueError", this is because subclass
449        # checking has recursion checking too.
450        with captured_output("stderr"):
451            try:
452                g()
453            except RuntimeError:
454                pass
455            except:
456                self.fail("Should have raised KeyError")
457            else:
458                self.fail("Should have raised KeyError")
459
460    def testUnicodeStrUsage(self):
461        # Make sure both instances and classes have a str and unicode
462        # representation.
463        self.failUnless(str(Exception))
464        self.failUnless(unicode(Exception))
465        self.failUnless(str(Exception('a')))
466        self.failUnless(unicode(Exception(u'a')))
467        self.failUnless(unicode(Exception(u'\xe1')))
468
469    def test_badisinstance(self):
470        # Bug #2542: if issubclass(e, MyException) raises an exception,
471        # it should be ignored
472        class Meta(type):
473            def __subclasscheck__(cls, subclass):
474                raise ValueError()
475
476        class MyException(Exception):
477            __metaclass__ = Meta
478            pass
479
480        with captured_output("stderr") as stderr:
481            try:
482                raise KeyError()
483            except MyException, e:
484                self.fail("exception should not be a MyException")
485            except KeyError:
486                pass
487            except:
488                self.fail("Should have raised KeyError")
489            else:
490                self.fail("Should have raised KeyError")
491
492        with captured_output("stderr") as stderr:
493            def g():
494                try:
495                    return g()
496                except RuntimeError:
497                    return sys.exc_info()
498            e, v, tb = g()
499            self.assert_(e is RuntimeError, e)
500            self.assert_("maximum recursion depth exceeded" in str(v), v)
501
502
503def test_main():
504    run_unittest(ExceptionTests)
505
506if __name__ == '__main__':
507    test_main()