a19c82d0665344072e22d16983225254155ee321
[profile/ivi/python.git] / Lib / test / test_exceptions.py
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
468
469 # Helper class used by TestSameStrAndUnicodeMsg
470 class ExcWithOverriddenStr(Exception):
471     """Subclass of Exception that accepts a keyword 'msg' arg that is
472     returned by __str__. 'msg' won't be included in self.args"""
473     def __init__(self, *args, **kwargs):
474         self.msg = kwargs.pop('msg') # msg should always be present
475         super(ExcWithOverriddenStr, self).__init__(*args, **kwargs)
476     def __str__(self):
477         return self.msg
478
479
480 class TestSameStrAndUnicodeMsg(unittest.TestCase):
481     """unicode(err) should return the same message of str(err). See #6108"""
482
483     def check_same_msg(self, exc, msg):
484         """Helper function that checks if str(exc) == unicode(exc) == msg"""
485         self.assertEqual(str(exc), msg)
486         self.assertEqual(str(exc), unicode(exc))
487
488     def test_builtin_exceptions(self):
489         """Check same msg for built-in exceptions"""
490         # These exceptions implement a __str__ method that uses the args
491         # to create a better error message. unicode(e) should return the same
492         # message.
493         exceptions = [
494             SyntaxError('invalid syntax', ('<string>', 1, 3, '2+*3')),
495             IOError(2, 'No such file or directory'),
496             KeyError('both should have the same quotes'),
497             UnicodeDecodeError('ascii', '\xc3\xa0', 0, 1,
498                                'ordinal not in range(128)'),
499             UnicodeEncodeError('ascii', u'\u1234', 0, 1,
500                                'ordinal not in range(128)')
501         ]
502         for exception in exceptions:
503             self.assertEqual(str(exception), unicode(exception))
504
505     def test_0_args(self):
506         """Check same msg for Exception with 0 args"""
507         # str() and unicode() on an Exception with no args should return an
508         # empty string
509         self.check_same_msg(Exception(), '')
510
511     def test_0_args_with_overridden___str__(self):
512         """Check same msg for exceptions with 0 args and overridden __str__"""
513         # str() and unicode() on an exception with overridden __str__ that
514         # returns an ascii-only string should return the same string
515         for msg in ('foo', u'foo'):
516             self.check_same_msg(ExcWithOverriddenStr(msg=msg), msg)
517
518         # if __str__ returns a non-ascii unicode string str() should fail
519         # but unicode() should return the unicode string
520         e = ExcWithOverriddenStr(msg=u'f\xf6\xf6') # no args
521         self.assertRaises(UnicodeEncodeError, str, e)
522         self.assertEqual(unicode(e), u'f\xf6\xf6')
523
524     def test_1_arg(self):
525         """Check same msg for Exceptions with 1 arg"""
526         for arg in ('foo', u'foo'):
527             self.check_same_msg(Exception(arg), arg)
528
529         # if __str__ is not overridden and self.args[0] is a non-ascii unicode
530         # string, str() should try to return str(self.args[0]) and fail.
531         # unicode() should return unicode(self.args[0]) and succeed.
532         e = Exception(u'f\xf6\xf6')
533         self.assertRaises(UnicodeEncodeError, str, e)
534         self.assertEqual(unicode(e), u'f\xf6\xf6')
535
536     def test_1_arg_with_overridden___str__(self):
537         """Check same msg for exceptions with overridden __str__ and 1 arg"""
538         # when __str__ is overridden and __unicode__ is not implemented
539         # unicode(e) returns the same as unicode(e.__str__()).
540         for msg in ('foo', u'foo'):
541             self.check_same_msg(ExcWithOverriddenStr('arg', msg=msg), msg)
542
543         # if __str__ returns a non-ascii unicode string, str() should fail
544         # but unicode() should succeed.
545         e = ExcWithOverriddenStr('arg', msg=u'f\xf6\xf6') # 1 arg
546         self.assertRaises(UnicodeEncodeError, str, e)
547         self.assertEqual(unicode(e), u'f\xf6\xf6')
548
549     def test_many_args(self):
550         """Check same msg for Exceptions with many args"""
551         argslist = [
552             (3, 'foo'),
553             (1, u'foo', 'bar'),
554             (4, u'f\xf6\xf6', u'bar', 'baz')
555         ]
556         # both str() and unicode() should return a repr() of the args
557         for args in argslist:
558             self.check_same_msg(Exception(*args), repr(args))
559
560     def test_many_args_with_overridden___str__(self):
561         """Check same msg for exceptions with overridden __str__ and many args"""
562         # if __str__ returns an ascii string / ascii unicode string
563         # both str() and unicode() should succeed
564         for msg in ('foo', u'foo'):
565             e = ExcWithOverriddenStr('arg1', u'arg2', u'f\xf6\xf6', msg=msg)
566             self.check_same_msg(e, msg)
567
568         # if __str__ returns a non-ascii unicode string, str() should fail
569         # but unicode() should succeed
570         e = ExcWithOverriddenStr('arg1', u'f\xf6\xf6', u'arg3', # 3 args
571                                  msg=u'f\xf6\xf6')
572         self.assertRaises(UnicodeEncodeError, str, e)
573         self.assertEqual(unicode(e), u'f\xf6\xf6')
574
575     @cpython_only
576     def test_exception_with_doc(self):
577         import _testcapi
578         doc2 = "This is a test docstring."
579         doc4 = "This is another test docstring."
580
581         self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
582                           "error1")
583
584         # test basic usage of PyErr_NewException
585         error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
586         self.assertIs(type(error1), type)
587         self.assertTrue(issubclass(error1, Exception))
588         self.assertIsNone(error1.__doc__)
589
590         # test with given docstring
591         error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
592         self.assertEqual(error2.__doc__, doc2)
593
594         # test with explicit base (without docstring)
595         error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
596                                                    base=error2)
597         self.assertTrue(issubclass(error3, error2))
598
599         # test with explicit base tuple
600         class C(object):
601             pass
602         error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
603                                                    (error3, C))
604         self.assertTrue(issubclass(error4, error3))
605         self.assertTrue(issubclass(error4, C))
606         self.assertEqual(error4.__doc__, doc4)
607
608         # test with explicit dictionary
609         error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
610                                                    error4, {'a': 1})
611         self.assertTrue(issubclass(error5, error4))
612         self.assertEqual(error5.a, 1)
613         self.assertEqual(error5.__doc__, "")
614
615
616 def test_main():
617     run_unittest(ExceptionTests, TestSameStrAndUnicodeMsg)
618
619 if __name__ == '__main__':
620     test_main()