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