1# Python test set -- part 5, built-in exceptions 2 3import os 4import sys 5import unittest 6import pickle, cPickle 7 8from test.test_support import (TESTFN, unlink, run_unittest, captured_stderr, 9 check_warnings, cpython_only) 10from test.test_pep352 import ignore_deprecation_warnings 11 12class 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 19class 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 507class 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 517class 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 709def test_main(): 710 run_unittest(ExceptionTests, TestSameStrAndUnicodeMsg) 711 712if __name__ == '__main__': 713 test_main() 714