Home | History | Annotate | Download | only in test
      1 # Python test set -- part 5, built-in exceptions
      2 
      3 import os
      4 import sys
      5 import unittest
      6 import pickle, cPickle
      7 
      8 from test.test_support import (TESTFN, unlink, run_unittest, captured_stderr,
      9                                check_warnings, cpython_only)
     10 from test.test_pep352 import ignore_deprecation_warnings
     11 
     12 class BrokenStrException(Exception):
     13     def __str__(self):
     14         raise Exception("str() is broken")
     15     __repr__ = __str__  # Python 2's PyErr_WriteUnraisable() uses repr()
     16 
     17 # XXX This is not really enough, each *operation* should be tested!
     18 
     19 class ExceptionTests(unittest.TestCase):
     20 
     21     def testReload(self):
     22         # Reloading the built-in exceptions module failed prior to Py2.2, while it
     23         # should act the same as reloading built-in sys.
     24         try:
     25             from imp import reload
     26             import exceptions
     27             reload(exceptions)
     28         except ImportError, e:
     29             self.fail("reloading exceptions: %s" % e)
     30 
     31     def raise_catch(self, exc, excname):
     32         try:
     33             raise exc, "spam"
     34         except exc, err:
     35             buf1 = str(err)
     36         try:
     37             raise exc("spam")
     38         except exc, err:
     39             buf2 = str(err)
     40         self.assertEqual(buf1, buf2)
     41         self.assertEqual(exc.__name__, excname)
     42 
     43     def testRaising(self):
     44         self.raise_catch(AttributeError, "AttributeError")
     45         self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")
     46 
     47         self.raise_catch(EOFError, "EOFError")
     48         fp = open(TESTFN, 'w')
     49         fp.close()
     50         fp = open(TESTFN, 'r')
     51         savestdin = sys.stdin
     52         try:
     53             try:
     54                 sys.stdin = fp
     55                 x = raw_input()
     56             except EOFError:
     57                 pass
     58         finally:
     59             sys.stdin = savestdin
     60             fp.close()
     61             unlink(TESTFN)
     62 
     63         self.raise_catch(IOError, "IOError")
     64         self.assertRaises(IOError, open, 'this file does not exist', 'r')
     65 
     66         self.raise_catch(ImportError, "ImportError")
     67         self.assertRaises(ImportError, __import__, "undefined_module")
     68 
     69         self.raise_catch(IndexError, "IndexError")
     70         x = []
     71         self.assertRaises(IndexError, x.__getitem__, 10)
     72 
     73         self.raise_catch(KeyError, "KeyError")
     74         x = {}
     75         self.assertRaises(KeyError, x.__getitem__, 'key')
     76 
     77         self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")
     78 
     79         self.raise_catch(MemoryError, "MemoryError")
     80 
     81         self.raise_catch(NameError, "NameError")
     82         try: x = undefined_variable
     83         except NameError: pass
     84 
     85         self.raise_catch(OverflowError, "OverflowError")
     86         x = 1
     87         for dummy in range(128):
     88             x += x  # this simply shouldn't blow up
     89 
     90         self.raise_catch(RuntimeError, "RuntimeError")
     91 
     92         self.raise_catch(SyntaxError, "SyntaxError")
     93         try: exec '/\n'
     94         except SyntaxError: pass
     95 
     96         self.raise_catch(IndentationError, "IndentationError")
     97 
     98         self.raise_catch(TabError, "TabError")
     99         # can only be tested under -tt, and is the only test for -tt
    100         #try: compile("try:\n\t1.0/0.0\n    \t1.0/0.0\nfinally:\n pass\n", '<string>', 'exec')
    101         #except TabError: pass
    102         #else: self.fail("TabError not raised")
    103 
    104         self.raise_catch(SystemError, "SystemError")
    105 
    106         self.raise_catch(SystemExit, "SystemExit")
    107         self.assertRaises(SystemExit, sys.exit, 0)
    108 
    109         self.raise_catch(TypeError, "TypeError")
    110         try: [] + ()
    111         except TypeError: pass
    112 
    113         self.raise_catch(ValueError, "ValueError")
    114         self.assertRaises(ValueError, chr, 10000)
    115 
    116         self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
    117         try: x = 1 // 0
    118         except ZeroDivisionError: pass
    119 
    120         self.raise_catch(Exception, "Exception")
    121         try: x = 1 // 0
    122         except Exception, e: pass
    123 
    124     def testSyntaxErrorMessage(self):
    125         # make sure the right exception message is raised for each of
    126         # these code fragments
    127 
    128         def ckmsg(src, msg):
    129             try:
    130                 compile(src, '<fragment>', 'exec')
    131             except SyntaxError, e:
    132                 if e.msg != msg:
    133                     self.fail("expected %s, got %s" % (msg, e.msg))
    134             else:
    135                 self.fail("failed to get expected SyntaxError")
    136 
    137         s = '''while 1:
    138             try:
    139                 pass
    140             finally:
    141                 continue'''
    142 
    143         if not sys.platform.startswith('java'):
    144             ckmsg(s, "'continue' not supported inside 'finally' clause")
    145 
    146         s = '''if 1:
    147         try:
    148             continue
    149         except:
    150             pass'''
    151 
    152         ckmsg(s, "'continue' not properly in loop")
    153         ckmsg("continue\n", "'continue' not properly in loop")
    154 
    155     @cpython_only
    156     def testSettingException(self):
    157         # test that setting an exception at the C level works even if the
    158         # exception object can't be constructed.
    159 
    160         class BadException:
    161             def __init__(self_):
    162                 raise RuntimeError, "can't instantiate BadException"
    163 
    164         def test_capi1():
    165             import _testcapi
    166             try:
    167                 _testcapi.raise_exception(BadException, 1)
    168             except TypeError, err:
    169                 exc, err, tb = sys.exc_info()
    170                 co = tb.tb_frame.f_code
    171                 self.assertEqual(co.co_name, "test_capi1")
    172                 self.assertTrue(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
    173             else:
    174                 self.fail("Expected exception")
    175 
    176         def test_capi2():
    177             import _testcapi
    178             try:
    179                 _testcapi.raise_exception(BadException, 0)
    180             except RuntimeError, err:
    181                 exc, err, tb = sys.exc_info()
    182                 co = tb.tb_frame.f_code
    183                 self.assertEqual(co.co_name, "__init__")
    184                 self.assertTrue(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
    185                 co2 = tb.tb_frame.f_back.f_code
    186                 self.assertEqual(co2.co_name, "test_capi2")
    187             else:
    188                 self.fail("Expected exception")
    189 
    190         if not sys.platform.startswith('java'):
    191             test_capi1()
    192             test_capi2()
    193 
    194     def test_WindowsError(self):
    195         try:
    196             WindowsError
    197         except NameError:
    198             pass
    199         else:
    200             self.assertEqual(str(WindowsError(1001)),
    201                                  "1001")
    202             self.assertEqual(str(WindowsError(1001, "message")),
    203                                  "[Error 1001] message")
    204             self.assertEqual(WindowsError(1001, "message").errno, 22)
    205             self.assertEqual(WindowsError(1001, "message").winerror, 1001)
    206 
    207     @ignore_deprecation_warnings
    208     def testAttributes(self):
    209         # test that exception attributes are happy
    210 
    211         exceptionList = [
    212             (BaseException, (), {'message' : '', 'args' : ()}),
    213             (BaseException, (1, ), {'message' : 1, 'args' : (1,)}),
    214             (BaseException, ('foo',),
    215                 {'message' : 'foo', 'args' : ('foo',)}),
    216             (BaseException, ('foo', 1),
    217                 {'message' : '', 'args' : ('foo', 1)}),
    218             (SystemExit, ('foo',),
    219                 {'message' : 'foo', 'args' : ('foo',), 'code' : 'foo'}),
    220             (IOError, ('foo',),
    221                 {'message' : 'foo', 'args' : ('foo',), 'filename' : None,
    222                  'errno' : None, 'strerror' : None}),
    223             (IOError, ('foo', 'bar'),
    224                 {'message' : '', 'args' : ('foo', 'bar'), 'filename' : None,
    225                  'errno' : 'foo', 'strerror' : 'bar'}),
    226             (IOError, ('foo', 'bar', 'baz'),
    227                 {'message' : '', 'args' : ('foo', 'bar'), 'filename' : 'baz',
    228                  'errno' : 'foo', 'strerror' : 'bar'}),
    229             (IOError, ('foo', 'bar', 'baz', 'quux'),
    230                 {'message' : '', 'args' : ('foo', 'bar', 'baz', 'quux')}),
    231             (EnvironmentError, ('errnoStr', 'strErrorStr', 'filenameStr'),
    232                 {'message' : '', 'args' : ('errnoStr', 'strErrorStr'),
    233                  'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
    234                  'filename' : 'filenameStr'}),
    235             (EnvironmentError, (1, 'strErrorStr', 'filenameStr'),
    236                 {'message' : '', 'args' : (1, 'strErrorStr'), 'errno' : 1,
    237                  'strerror' : 'strErrorStr', 'filename' : 'filenameStr'}),
    238             (SyntaxError, (), {'message' : '', 'msg' : None, 'text' : None,
    239                 'filename' : None, 'lineno' : None, 'offset' : None,
    240                 'print_file_and_line' : None}),
    241             (SyntaxError, ('msgStr',),
    242                 {'message' : 'msgStr', 'args' : ('msgStr',), 'text' : None,
    243                  'print_file_and_line' : None, 'msg' : 'msgStr',
    244                  'filename' : None, 'lineno' : None, 'offset' : None}),
    245             (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
    246                            'textStr')),
    247                 {'message' : '', 'offset' : 'offsetStr', 'text' : 'textStr',
    248                  'args' : ('msgStr', ('filenameStr', 'linenoStr',
    249                                       'offsetStr', 'textStr')),
    250                  'print_file_and_line' : None, 'msg' : 'msgStr',
    251                  'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
    252             (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
    253                            'textStr', 'print_file_and_lineStr'),
    254                 {'message' : '', 'text' : None,
    255                  'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
    256                            'textStr', 'print_file_and_lineStr'),
    257                  'print_file_and_line' : None, 'msg' : 'msgStr',
    258                  'filename' : None, 'lineno' : None, 'offset' : None}),
    259             (UnicodeError, (), {'message' : '', 'args' : (),}),
    260             (UnicodeEncodeError, ('ascii', u'a', 0, 1, 'ordinal not in range'),
    261                 {'message' : '', 'args' : ('ascii', u'a', 0, 1,
    262                                            'ordinal not in range'),
    263                  'encoding' : 'ascii', 'object' : u'a',
    264                  'start' : 0, 'reason' : 'ordinal not in range'}),
    265             (UnicodeDecodeError, ('ascii', '\xff', 0, 1, 'ordinal not in range'),
    266                 {'message' : '', 'args' : ('ascii', '\xff', 0, 1,
    267                                            'ordinal not in range'),
    268                  'encoding' : 'ascii', 'object' : '\xff',
    269                  'start' : 0, 'reason' : 'ordinal not in range'}),
    270             (UnicodeTranslateError, (u"\u3042", 0, 1, "ouch"),
    271                 {'message' : '', 'args' : (u'\u3042', 0, 1, 'ouch'),
    272                  'object' : u'\u3042', 'reason' : 'ouch',
    273                  'start' : 0, 'end' : 1}),
    274         ]
    275         try:
    276             exceptionList.append(
    277                 (WindowsError, (1, 'strErrorStr', 'filenameStr'),
    278                     {'message' : '', 'args' : (1, 'strErrorStr'),
    279                      'strerror' : 'strErrorStr', 'winerror' : 1,
    280                      'errno' : 22, 'filename' : 'filenameStr'})
    281             )
    282         except NameError:
    283             pass
    284 
    285         for exc, args, expected in exceptionList:
    286             try:
    287                 raise exc(*args)
    288             except BaseException, e:
    289                 if type(e) is not exc:
    290                     raise
    291                 # Verify module name
    292                 self.assertEqual(type(e).__module__, 'exceptions')
    293                 # Verify no ref leaks in Exc_str()
    294                 s = str(e)
    295                 for checkArgName in expected:
    296                     self.assertEqual(repr(getattr(e, checkArgName)),
    297                                      repr(expected[checkArgName]),
    298                                      'exception "%s", attribute "%s"' %
    299                                       (repr(e), checkArgName))
    300 
    301                 # test for pickling support
    302                 for p in pickle, cPickle:
    303                     for protocol in range(p.HIGHEST_PROTOCOL + 1):
    304                         new = p.loads(p.dumps(e, protocol))
    305                         for checkArgName in expected:
    306                             got = repr(getattr(new, checkArgName))
    307                             want = repr(expected[checkArgName])
    308                             self.assertEqual(got, want,
    309                                              'pickled "%r", attribute "%s"' %
    310                                              (e, checkArgName))
    311 
    312 
    313     def testDeprecatedMessageAttribute(self):
    314         # Accessing BaseException.message and relying on its value set by
    315         # BaseException.__init__ triggers a deprecation warning.
    316         exc = BaseException("foo")
    317         with check_warnings(("BaseException.message has been deprecated "
    318                              "as of Python 2.6", DeprecationWarning)) as w:
    319             self.assertEqual(exc.message, "foo")
    320         self.assertEqual(len(w.warnings), 1)
    321 
    322     def testRegularMessageAttribute(self):
    323         # Accessing BaseException.message after explicitly setting a value
    324         # for it does not trigger a deprecation warning.
    325         exc = BaseException("foo")
    326         exc.message = "bar"
    327         with check_warnings(quiet=True) as w:
    328             self.assertEqual(exc.message, "bar")
    329         self.assertEqual(len(w.warnings), 0)
    330         # Deleting the message is supported, too.
    331         del exc.message
    332         with self.assertRaises(AttributeError):
    333             exc.message
    334 
    335     @ignore_deprecation_warnings
    336     def testPickleMessageAttribute(self):
    337         # Pickling with message attribute must work, as well.
    338         e = Exception("foo")
    339         f = Exception("foo")
    340         f.message = "bar"
    341         for p in pickle, cPickle:
    342             ep = p.loads(p.dumps(e))
    343             self.assertEqual(ep.message, "foo")
    344             fp = p.loads(p.dumps(f))
    345             self.assertEqual(fp.message, "bar")
    346 
    347     @ignore_deprecation_warnings
    348     def testSlicing(self):
    349         # Test that you can slice an exception directly instead of requiring
    350         # going through the 'args' attribute.
    351         args = (1, 2, 3)
    352         exc = BaseException(*args)
    353         self.assertEqual(exc[:], args)
    354         self.assertEqual(exc.args[:], args)
    355 
    356     def testKeywordArgs(self):
    357         # test that builtin exception don't take keyword args,
    358         # but user-defined subclasses can if they want
    359         self.assertRaises(TypeError, BaseException, a=1)
    360 
    361         class DerivedException(BaseException):
    362             def __init__(self, fancy_arg):
    363                 BaseException.__init__(self)
    364                 self.fancy_arg = fancy_arg
    365 
    366         x = DerivedException(fancy_arg=42)
    367         self.assertEqual(x.fancy_arg, 42)
    368 
    369     def testInfiniteRecursion(self):
    370         def f():
    371             return f()
    372         self.assertRaises(RuntimeError, f)
    373 
    374         def g():
    375             try:
    376                 return g()
    377             except ValueError:
    378                 return -1
    379 
    380         # The test prints an unraisable recursion error when
    381         # doing "except ValueError", this is because subclass
    382         # checking has recursion checking too.
    383         with captured_stderr():
    384             try:
    385                 g()
    386             except RuntimeError:
    387                 pass
    388             except:
    389                 self.fail("Should have raised KeyError")
    390             else:
    391                 self.fail("Should have raised KeyError")
    392 
    393     def testUnicodeStrUsage(self):
    394         # Make sure both instances and classes have a str and unicode
    395         # representation.
    396         self.assertTrue(str(Exception))
    397         self.assertTrue(unicode(Exception))
    398         self.assertTrue(str(Exception('a')))
    399         self.assertTrue(unicode(Exception(u'a')))
    400         self.assertTrue(unicode(Exception(u'\xe1')))
    401 
    402     def testUnicodeChangeAttributes(self):
    403         # See issue 7309. This was a crasher.
    404 
    405         u = UnicodeEncodeError('baz', u'xxxxx', 1, 5, 'foo')
    406         self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: foo")
    407         u.end = 2
    408         self.assertEqual(str(u), "'baz' codec can't encode character u'\\x78' in position 1: foo")
    409         u.end = 5
    410         u.reason = 0x345345345345345345
    411         self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: 965230951443685724997")
    412         u.encoding = 4000
    413         self.assertEqual(str(u), "'4000' codec can't encode characters in position 1-4: 965230951443685724997")
    414         u.start = 1000
    415         self.assertEqual(str(u), "'4000' codec can't encode characters in position 1000-4: 965230951443685724997")
    416 
    417         u = UnicodeDecodeError('baz', 'xxxxx', 1, 5, 'foo')
    418         self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: foo")
    419         u.end = 2
    420         self.assertEqual(str(u), "'baz' codec can't decode byte 0x78 in position 1: foo")
    421         u.end = 5
    422         u.reason = 0x345345345345345345
    423         self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: 965230951443685724997")
    424         u.encoding = 4000
    425         self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1-4: 965230951443685724997")
    426         u.start = 1000
    427         self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1000-4: 965230951443685724997")
    428 
    429         u = UnicodeTranslateError(u'xxxx', 1, 5, 'foo')
    430         self.assertEqual(str(u), "can't translate characters in position 1-4: foo")
    431         u.end = 2
    432         self.assertEqual(str(u), "can't translate character u'\\x78' in position 1: foo")
    433         u.end = 5
    434         u.reason = 0x345345345345345345
    435         self.assertEqual(str(u), "can't translate characters in position 1-4: 965230951443685724997")
    436         u.start = 1000
    437         self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997")
    438 
    439     def test_unicode_errors_no_object(self):
    440         # See issue #21134.
    441         klasses = UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError
    442         for klass in klasses:
    443             self.assertEqual(str(klass.__new__(klass)), "")
    444 
    445     def test_badisinstance(self):
    446         # Bug #2542: if issubclass(e, MyException) raises an exception,
    447         # it should be ignored
    448         class Meta(type):
    449             def __subclasscheck__(cls, subclass):
    450                 raise ValueError()
    451 
    452         class MyException(Exception):
    453             __metaclass__ = Meta
    454             pass
    455 
    456         with captured_stderr() as stderr:
    457             try:
    458                 raise KeyError()
    459             except MyException, e:
    460                 self.fail("exception should not be a MyException")
    461             except KeyError:
    462                 pass
    463             except:
    464                 self.fail("Should have raised KeyError")
    465             else:
    466                 self.fail("Should have raised KeyError")
    467 
    468         with captured_stderr() as stderr:
    469             def g():
    470                 try:
    471                     return g()
    472                 except RuntimeError:
    473                     return sys.exc_info()
    474             e, v, tb = g()
    475             self.assertTrue(e is RuntimeError, e)
    476             self.assertIn("maximum recursion depth exceeded", str(v))
    477 
    478     def test_new_returns_invalid_instance(self):
    479         # See issue #11627.
    480         class MyException(Exception):
    481             def __new__(cls, *args):
    482                 return object()
    483 
    484         with self.assertRaises(TypeError):
    485             raise MyException
    486 
    487     def test_assert_with_tuple_arg(self):
    488         try:
    489             assert False, (3,)
    490         except AssertionError as e:
    491             self.assertEqual(str(e), "(3,)")
    492 
    493     def test_bad_exception_clearing(self):
    494         # See issue 16445: use of Py_XDECREF instead of Py_CLEAR in
    495         # BaseException_set_message gave a possible way to segfault the
    496         # interpreter.
    497         class Nasty(str):
    498             def __del__(message):
    499                 del e.message
    500 
    501         e = ValueError(Nasty("msg"))
    502         e.args = ()
    503         del e.message
    504 
    505 
    506 # Helper class used by TestSameStrAndUnicodeMsg
    507 class ExcWithOverriddenStr(Exception):
    508     """Subclass of Exception that accepts a keyword 'msg' arg that is
    509     returned by __str__. 'msg' won't be included in self.args"""
    510     def __init__(self, *args, **kwargs):
    511         self.msg = kwargs.pop('msg') # msg should always be present
    512         super(ExcWithOverriddenStr, self).__init__(*args, **kwargs)
    513     def __str__(self):
    514         return self.msg
    515 
    516 
    517 class TestSameStrAndUnicodeMsg(unittest.TestCase):
    518     """unicode(err) should return the same message of str(err). See #6108"""
    519 
    520     def check_same_msg(self, exc, msg):
    521         """Helper function that checks if str(exc) == unicode(exc) == msg"""
    522         self.assertEqual(str(exc), msg)
    523         self.assertEqual(str(exc), unicode(exc))
    524 
    525     def test_builtin_exceptions(self):
    526         """Check same msg for built-in exceptions"""
    527         # These exceptions implement a __str__ method that uses the args
    528         # to create a better error message. unicode(e) should return the same
    529         # message.
    530         exceptions = [
    531             SyntaxError('invalid syntax', ('<string>', 1, 3, '2+*3')),
    532             IOError(2, 'No such file or directory'),
    533             KeyError('both should have the same quotes'),
    534             UnicodeDecodeError('ascii', '\xc3\xa0', 0, 1,
    535                                'ordinal not in range(128)'),
    536             UnicodeEncodeError('ascii', u'\u1234', 0, 1,
    537                                'ordinal not in range(128)')
    538         ]
    539         for exception in exceptions:
    540             self.assertEqual(str(exception), unicode(exception))
    541 
    542     def test_0_args(self):
    543         """Check same msg for Exception with 0 args"""
    544         # str() and unicode() on an Exception with no args should return an
    545         # empty string
    546         self.check_same_msg(Exception(), '')
    547 
    548     def test_0_args_with_overridden___str__(self):
    549         """Check same msg for exceptions with 0 args and overridden __str__"""
    550         # str() and unicode() on an exception with overridden __str__ that
    551         # returns an ascii-only string should return the same string
    552         for msg in ('foo', u'foo'):
    553             self.check_same_msg(ExcWithOverriddenStr(msg=msg), msg)
    554 
    555         # if __str__ returns a non-ascii unicode string str() should fail
    556         # but unicode() should return the unicode string
    557         e = ExcWithOverriddenStr(msg=u'f\xf6\xf6') # no args
    558         self.assertRaises(UnicodeEncodeError, str, e)
    559         self.assertEqual(unicode(e), u'f\xf6\xf6')
    560 
    561     def test_1_arg(self):
    562         """Check same msg for Exceptions with 1 arg"""
    563         for arg in ('foo', u'foo'):
    564             self.check_same_msg(Exception(arg), arg)
    565 
    566         # if __str__ is not overridden and self.args[0] is a non-ascii unicode
    567         # string, str() should try to return str(self.args[0]) and fail.
    568         # unicode() should return unicode(self.args[0]) and succeed.
    569         e = Exception(u'f\xf6\xf6')
    570         self.assertRaises(UnicodeEncodeError, str, e)
    571         self.assertEqual(unicode(e), u'f\xf6\xf6')
    572 
    573     def test_1_arg_with_overridden___str__(self):
    574         """Check same msg for exceptions with overridden __str__ and 1 arg"""
    575         # when __str__ is overridden and __unicode__ is not implemented
    576         # unicode(e) returns the same as unicode(e.__str__()).
    577         for msg in ('foo', u'foo'):
    578             self.check_same_msg(ExcWithOverriddenStr('arg', msg=msg), msg)
    579 
    580         # if __str__ returns a non-ascii unicode string, str() should fail
    581         # but unicode() should succeed.
    582         e = ExcWithOverriddenStr('arg', msg=u'f\xf6\xf6') # 1 arg
    583         self.assertRaises(UnicodeEncodeError, str, e)
    584         self.assertEqual(unicode(e), u'f\xf6\xf6')
    585 
    586     def test_many_args(self):
    587         """Check same msg for Exceptions with many args"""
    588         argslist = [
    589             (3, 'foo'),
    590             (1, u'foo', 'bar'),
    591             (4, u'f\xf6\xf6', u'bar', 'baz')
    592         ]
    593         # both str() and unicode() should return a repr() of the args
    594         for args in argslist:
    595             self.check_same_msg(Exception(*args), repr(args))
    596 
    597     def test_many_args_with_overridden___str__(self):
    598         """Check same msg for exceptions with overridden __str__ and many args"""
    599         # if __str__ returns an ascii string / ascii unicode string
    600         # both str() and unicode() should succeed
    601         for msg in ('foo', u'foo'):
    602             e = ExcWithOverriddenStr('arg1', u'arg2', u'f\xf6\xf6', msg=msg)
    603             self.check_same_msg(e, msg)
    604 
    605         # if __str__ returns a non-ascii unicode string, str() should fail
    606         # but unicode() should succeed
    607         e = ExcWithOverriddenStr('arg1', u'f\xf6\xf6', u'arg3', # 3 args
    608                                  msg=u'f\xf6\xf6')
    609         self.assertRaises(UnicodeEncodeError, str, e)
    610         self.assertEqual(unicode(e), u'f\xf6\xf6')
    611 
    612     @cpython_only
    613     def test_exception_with_doc(self):
    614         import _testcapi
    615         doc2 = "This is a test docstring."
    616         doc4 = "This is another test docstring."
    617 
    618         self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
    619                           "error1")
    620 
    621         # test basic usage of PyErr_NewException
    622         error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
    623         self.assertIs(type(error1), type)
    624         self.assertTrue(issubclass(error1, Exception))
    625         self.assertIsNone(error1.__doc__)
    626 
    627         # test with given docstring
    628         error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
    629         self.assertEqual(error2.__doc__, doc2)
    630 
    631         # test with explicit base (without docstring)
    632         error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
    633                                                    base=error2)
    634         self.assertTrue(issubclass(error3, error2))
    635 
    636         # test with explicit base tuple
    637         class C(object):
    638             pass
    639         error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
    640                                                    (error3, C))
    641         self.assertTrue(issubclass(error4, error3))
    642         self.assertTrue(issubclass(error4, C))
    643         self.assertEqual(error4.__doc__, doc4)
    644 
    645         # test with explicit dictionary
    646         error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
    647                                                    error4, {'a': 1})
    648         self.assertTrue(issubclass(error5, error4))
    649         self.assertEqual(error5.a, 1)
    650         self.assertEqual(error5.__doc__, "")
    651 
    652     def test_unraisable(self):
    653         # Issue #22836: PyErr_WriteUnraisable() should give sensible reports
    654         class BrokenDel:
    655             def __del__(self):
    656                 exc = ValueError("del is broken")
    657                 # In Python 3, the following line would be in the report:
    658                 raise exc
    659 
    660         class BrokenRepr(BrokenDel):
    661             def __repr__(self):
    662                 raise AttributeError("repr() is broken")
    663 
    664         class BrokenExceptionDel:
    665             def __del__(self):
    666                 exc = BrokenStrException()
    667                 # In Python 3, the following line would be in the report:
    668                 raise exc
    669 
    670         for test_class in (BrokenDel, BrokenRepr, BrokenExceptionDel):
    671             obj = test_class()
    672             with captured_stderr() as stderr:
    673                 del obj
    674             report = stderr.getvalue()
    675             self.assertRegexpMatches(report, "Exception.* ignored")
    676             if test_class is BrokenRepr:
    677                 self.assertIn("<object repr() failed>", report)
    678             else:
    679                 self.assertIn("__del__", report)
    680             if test_class is BrokenExceptionDel:
    681                 self.assertIn("BrokenStrException", report)
    682                 self.assertIn("<exception repr() failed>", report)
    683             else:
    684                 self.assertIn("ValueError", report)
    685                 self.assertIn("del is broken", report)
    686             self.assertTrue(report.endswith("\n"))
    687 
    688     def test_unhandled(self):
    689         # Check for sensible reporting of unhandled exceptions
    690         for exc_type in (ValueError, BrokenStrException):
    691             try:
    692                 exc = exc_type("test message")
    693                 # The following line is included in the traceback report:
    694                 raise exc
    695             except exc_type:
    696                 with captured_stderr() as stderr:
    697                     sys.__excepthook__(*sys.exc_info())
    698             report = stderr.getvalue()
    699             self.assertIn("test_exceptions.py", report)
    700             self.assertIn("raise exc", report)
    701             self.assertIn(exc_type.__name__, report)
    702             if exc_type is BrokenStrException:
    703                 self.assertIn("<exception str() failed>", report)
    704             else:
    705                 self.assertIn("test message", report)
    706             self.assertTrue(report.endswith("\n"))
    707 
    708 
    709 def test_main():
    710     run_unittest(ExceptionTests, TestSameStrAndUnicodeMsg)
    711 
    712 if __name__ == '__main__':
    713     test_main()
    714