test_exceptions.py 38.9 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2
# Python test set -- part 5, built-in exceptions

3 4
import os
import sys
5
import unittest
6
import pickle
7
import weakref
8
import errno
9

10
from test.support import (TESTFN, captured_stderr, check_impl_detail,
Philip Jenvey's avatar
Philip Jenvey committed
11
                          check_warnings, cpython_only, gc_collect, run_unittest,
12
                          no_tracing, unlink, import_module)
13

14 15 16 17 18 19 20 21 22
class NaiveException(Exception):
    def __init__(self, x):
        self.x = x

class SlottedNaiveException(Exception):
    __slots__ = ('x',)
    def __init__(self, x):
        self.x = x

23 24 25 26
class BrokenStrException(Exception):
    def __str__(self):
        raise Exception("str() is broken")

Guido van Rossum's avatar
Guido van Rossum committed
27 28
# XXX This is not really enough, each *operation* should be tested!

29 30 31 32
class ExceptionTests(unittest.TestCase):

    def raise_catch(self, exc, excname):
        try:
33
            raise exc("spam")
34
        except exc as err:
35 36 37
            buf1 = str(err)
        try:
            raise exc("spam")
38
        except exc as err:
39
            buf2 = str(err)
40 41
        self.assertEqual(buf1, buf2)
        self.assertEqual(exc.__name__, excname)
42 43 44 45 46 47 48 49 50 51 52 53 54

    def testRaising(self):
        self.raise_catch(AttributeError, "AttributeError")
        self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")

        self.raise_catch(EOFError, "EOFError")
        fp = open(TESTFN, 'w')
        fp.close()
        fp = open(TESTFN, 'r')
        savestdin = sys.stdin
        try:
            try:
                import marshal
55
                marshal.loads(b'')
56 57 58 59 60 61 62
            except EOFError:
                pass
        finally:
            sys.stdin = savestdin
            fp.close()
            unlink(TESTFN)

63 64
        self.raise_catch(OSError, "OSError")
        self.assertRaises(OSError, open, 'this file does not exist', 'r')
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

        self.raise_catch(ImportError, "ImportError")
        self.assertRaises(ImportError, __import__, "undefined_module")

        self.raise_catch(IndexError, "IndexError")
        x = []
        self.assertRaises(IndexError, x.__getitem__, 10)

        self.raise_catch(KeyError, "KeyError")
        x = {}
        self.assertRaises(KeyError, x.__getitem__, 'key')

        self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")

        self.raise_catch(MemoryError, "MemoryError")

        self.raise_catch(NameError, "NameError")
        try: x = undefined_variable
        except NameError: pass

        self.raise_catch(OverflowError, "OverflowError")
        x = 1
        for dummy in range(128):
            x += x  # this simply shouldn't blow up

        self.raise_catch(RuntimeError, "RuntimeError")
91
        self.raise_catch(RecursionError, "RecursionError")
92 93

        self.raise_catch(SyntaxError, "SyntaxError")
94
        try: exec('/\n')
95 96 97 98 99
        except SyntaxError: pass

        self.raise_catch(IndentationError, "IndentationError")

        self.raise_catch(TabError, "TabError")
100 101 102 103
        try: compile("try:\n\t1/0\n    \t1/0\nfinally:\n pass\n",
                     '<string>', 'exec')
        except TabError: pass
        else: self.fail("TabError not raised")
104 105 106 107 108 109 110 111 112 113 114

        self.raise_catch(SystemError, "SystemError")

        self.raise_catch(SystemExit, "SystemExit")
        self.assertRaises(SystemExit, sys.exit, 0)

        self.raise_catch(TypeError, "TypeError")
        try: [] + ()
        except TypeError: pass

        self.raise_catch(ValueError, "ValueError")
115
        self.assertRaises(ValueError, chr, 17<<16)
116 117 118 119 120 121 122

        self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
        try: x = 1/0
        except ZeroDivisionError: pass

        self.raise_catch(Exception, "Exception")
        try: x = 1/0
123
        except Exception as e: pass
124

125 126
        self.raise_catch(StopAsyncIteration, "StopAsyncIteration")

127 128 129 130 131 132 133
    def testSyntaxErrorMessage(self):
        # make sure the right exception message is raised for each of
        # these code fragments

        def ckmsg(src, msg):
            try:
                compile(src, '<fragment>', 'exec')
134
            except SyntaxError as e:
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
                if e.msg != msg:
                    self.fail("expected %s, got %s" % (msg, e.msg))
            else:
                self.fail("failed to get expected SyntaxError")

        s = '''while 1:
            try:
                pass
            finally:
                continue'''

        if not sys.platform.startswith('java'):
            ckmsg(s, "'continue' not supported inside 'finally' clause")

        s = '''if 1:
        try:
            continue
        except:
            pass'''

        ckmsg(s, "'continue' not properly in loop")
        ckmsg("continue\n", "'continue' not properly in loop")

158 159 160 161 162 163 164 165 166 167 168 169 170
    def testSyntaxErrorOffset(self):
        def check(src, lineno, offset):
            with self.assertRaises(SyntaxError) as cm:
                compile(src, '<fragment>', 'exec')
            self.assertEqual(cm.exception.lineno, lineno)
            self.assertEqual(cm.exception.offset, offset)

        check('def fact(x):\n\treturn x!\n', 2, 10)
        check('1 +\n', 1, 4)
        check('def spam():\n  print(1)\n print(2)', 3, 10)
        check('Python = "Python" +', 1, 20)
        check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20)

171
    @cpython_only
172 173 174 175 176 177
    def testSettingException(self):
        # test that setting an exception at the C level works even if the
        # exception object can't be constructed.

        class BadException(Exception):
            def __init__(self_):
178
                raise RuntimeError("can't instantiate BadException")
179 180 181 182 183 184 185 186

        class InvalidException:
            pass

        def test_capi1():
            import _testcapi
            try:
                _testcapi.raise_exception(BadException, 1)
187
            except TypeError as err:
188 189
                exc, err, tb = sys.exc_info()
                co = tb.tb_frame.f_code
190
                self.assertEqual(co.co_name, "test_capi1")
191
                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
192 193 194 195 196 197 198
            else:
                self.fail("Expected exception")

        def test_capi2():
            import _testcapi
            try:
                _testcapi.raise_exception(BadException, 0)
199
            except RuntimeError as err:
200 201
                exc, err, tb = sys.exc_info()
                co = tb.tb_frame.f_code
202
                self.assertEqual(co.co_name, "__init__")
203
                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
204
                co2 = tb.tb_frame.f_back.f_code
205
                self.assertEqual(co2.co_name, "test_capi2")
206 207 208 209 210 211 212 213 214 215 216 217 218
            else:
                self.fail("Expected exception")

        def test_capi3():
            import _testcapi
            self.assertRaises(SystemError, _testcapi.raise_exception,
                              InvalidException, 1)

        if not sys.platform.startswith('java'):
            test_capi1()
            test_capi2()
            test_capi3()

219
    def test_WindowsError(self):
220
        try:
221 222 223 224
            WindowsError
        except NameError:
            pass
        else:
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
            self.assertIs(WindowsError, OSError)
            self.assertEqual(str(OSError(1001)), "1001")
            self.assertEqual(str(OSError(1001, "message")),
                             "[Errno 1001] message")
            # POSIX errno (9 aka EBADF) is untranslated
            w = OSError(9, 'foo', 'bar')
            self.assertEqual(w.errno, 9)
            self.assertEqual(w.winerror, None)
            self.assertEqual(str(w), "[Errno 9] foo: 'bar'")
            # ERROR_PATH_NOT_FOUND (win error 3) becomes ENOENT (2)
            w = OSError(0, 'foo', 'bar', 3)
            self.assertEqual(w.errno, 2)
            self.assertEqual(w.winerror, 3)
            self.assertEqual(w.strerror, 'foo')
            self.assertEqual(w.filename, 'bar')
240
            self.assertEqual(w.filename2, None)
241
            self.assertEqual(str(w), "[WinError 3] foo: 'bar'")
242 243 244 245 246 247
            # Unknown win error becomes EINVAL (22)
            w = OSError(0, 'foo', None, 1001)
            self.assertEqual(w.errno, 22)
            self.assertEqual(w.winerror, 1001)
            self.assertEqual(w.strerror, 'foo')
            self.assertEqual(w.filename, None)
248
            self.assertEqual(w.filename2, None)
249
            self.assertEqual(str(w), "[WinError 1001] foo")
250 251 252 253 254 255
            # Non-numeric "errno"
            w = OSError('bar', 'foo')
            self.assertEqual(w.errno, 'bar')
            self.assertEqual(w.winerror, None)
            self.assertEqual(w.strerror, 'foo')
            self.assertEqual(w.filename, None)
256
            self.assertEqual(w.filename2, None)
257

258 259
    @unittest.skipUnless(sys.platform == 'win32',
                         'test specific to Windows')
260 261
    def test_windows_message(self):
        """Should fill in unknown error code in Windows error message"""
262 263 264 265 266
        ctypes = import_module('ctypes')
        # this error code has no message, Python formats it as hexadecimal
        code = 3765269347
        with self.assertRaisesRegex(OSError, 'Windows Error 0x%x' % code):
            ctypes.pythonapi.PyErr_SetFromWindowsErr(code)
267

268 269
    def testAttributes(self):
        # test that exception attributes are happy
270 271

        exceptionList = [
272 273
            (BaseException, (), {'args' : ()}),
            (BaseException, (1, ), {'args' : (1,)}),
274
            (BaseException, ('foo',),
275
                {'args' : ('foo',)}),
276
            (BaseException, ('foo', 1),
277
                {'args' : ('foo', 1)}),
278
            (SystemExit, ('foo',),
279
                {'args' : ('foo',), 'code' : 'foo'}),
280
            (OSError, ('foo',),
281
                {'args' : ('foo',), 'filename' : None, 'filename2' : None,
282
                 'errno' : None, 'strerror' : None}),
283
            (OSError, ('foo', 'bar'),
284 285
                {'args' : ('foo', 'bar'),
                 'filename' : None, 'filename2' : None,
286
                 'errno' : 'foo', 'strerror' : 'bar'}),
287
            (OSError, ('foo', 'bar', 'baz'),
288 289
                {'args' : ('foo', 'bar'),
                 'filename' : 'baz', 'filename2' : None,
290
                 'errno' : 'foo', 'strerror' : 'bar'}),
291 292
            (OSError, ('foo', 'bar', 'baz', None, 'quux'),
                {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}),
293
            (OSError, ('errnoStr', 'strErrorStr', 'filenameStr'),
294
                {'args' : ('errnoStr', 'strErrorStr'),
295 296
                 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
                 'filename' : 'filenameStr'}),
297
            (OSError, (1, 'strErrorStr', 'filenameStr'),
298
                {'args' : (1, 'strErrorStr'), 'errno' : 1,
299 300
                 'strerror' : 'strErrorStr',
                 'filename' : 'filenameStr', 'filename2' : None}),
301
            (SyntaxError, (), {'msg' : None, 'text' : None,
302 303
                'filename' : None, 'lineno' : None, 'offset' : None,
                'print_file_and_line' : None}),
304
            (SyntaxError, ('msgStr',),
305
                {'args' : ('msgStr',), 'text' : None,
306 307 308 309
                 'print_file_and_line' : None, 'msg' : 'msgStr',
                 'filename' : None, 'lineno' : None, 'offset' : None}),
            (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
                           'textStr')),
310
                {'offset' : 'offsetStr', 'text' : 'textStr',
311 312 313 314 315 316
                 'args' : ('msgStr', ('filenameStr', 'linenoStr',
                                      'offsetStr', 'textStr')),
                 'print_file_and_line' : None, 'msg' : 'msgStr',
                 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
            (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
                           'textStr', 'print_file_and_lineStr'),
317
                {'text' : None,
318 319 320 321
                 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
                           'textStr', 'print_file_and_lineStr'),
                 'print_file_and_line' : None, 'msg' : 'msgStr',
                 'filename' : None, 'lineno' : None, 'offset' : None}),
322
            (UnicodeError, (), {'args' : (),}),
323 324
            (UnicodeEncodeError, ('ascii', 'a', 0, 1,
                                  'ordinal not in range'),
325
                {'args' : ('ascii', 'a', 0, 1,
326
                                           'ordinal not in range'),
327
                 'encoding' : 'ascii', 'object' : 'a',
328
                 'start' : 0, 'reason' : 'ordinal not in range'}),
329
            (UnicodeDecodeError, ('ascii', bytearray(b'\xff'), 0, 1,
330
                                  'ordinal not in range'),
331
                {'args' : ('ascii', bytearray(b'\xff'), 0, 1,
332 333 334
                                           'ordinal not in range'),
                 'encoding' : 'ascii', 'object' : b'\xff',
                 'start' : 0, 'reason' : 'ordinal not in range'}),
335 336
            (UnicodeDecodeError, ('ascii', b'\xff', 0, 1,
                                  'ordinal not in range'),
337
                {'args' : ('ascii', b'\xff', 0, 1,
338
                                           'ordinal not in range'),
339
                 'encoding' : 'ascii', 'object' : b'\xff',
340
                 'start' : 0, 'reason' : 'ordinal not in range'}),
341
            (UnicodeTranslateError, ("\u3042", 0, 1, "ouch"),
342
                {'args' : ('\u3042', 0, 1, 'ouch'),
343
                 'object' : '\u3042', 'reason' : 'ouch',
344
                 'start' : 0, 'end' : 1}),
345 346 347 348
            (NaiveException, ('foo',),
                {'args': ('foo',), 'x': 'foo'}),
            (SlottedNaiveException, ('foo',),
                {'args': ('foo',), 'x': 'foo'}),
349
        ]
350
        try:
351
            # More tests are in test_WindowsError
352 353
            exceptionList.append(
                (WindowsError, (1, 'strErrorStr', 'filenameStr'),
354
                    {'args' : (1, 'strErrorStr'),
355
                     'strerror' : 'strErrorStr', 'winerror' : None,
356 357
                     'errno' : 1,
                     'filename' : 'filenameStr', 'filename2' : None})
358
            )
359 360
        except NameError:
            pass
361

362 363 364 365
        for exc, args, expected in exceptionList:
            try:
                e = exc(*args)
            except:
366
                print("\nexc=%r, args=%r" % (exc, args), file=sys.stderr)
367 368 369
                raise
            else:
                # Verify module name
370 371
                if not type(e).__name__.endswith('NaiveException'):
                    self.assertEqual(type(e).__module__, 'builtins')
372 373 374 375
                # Verify no ref leaks in Exc_str()
                s = str(e)
                for checkArgName in expected:
                    value = getattr(e, checkArgName)
376 377 378 379 380
                    self.assertEqual(repr(value),
                                     repr(expected[checkArgName]),
                                     '%r.%s == %r, expected %r' % (
                                     e, checkArgName,
                                     value, expected[checkArgName]))
381 382

                # test for pickling support
383
                for p in [pickle]:
384 385 386 387 388 389
                    for protocol in range(p.HIGHEST_PROTOCOL + 1):
                        s = p.dumps(e, protocol)
                        new = p.loads(s)
                        for checkArgName in expected:
                            got = repr(getattr(new, checkArgName))
                            want = repr(expected[checkArgName])
390 391 392
                            self.assertEqual(got, want,
                                             'pickled "%r", attribute "%s' %
                                             (e, checkArgName))
393

394 395 396 397 398 399 400
    def testWithTraceback(self):
        try:
            raise IndexError(4)
        except:
            tb = sys.exc_info()[2]

        e = BaseException().with_traceback(tb)
401
        self.assertIsInstance(e, BaseException)
402 403 404
        self.assertEqual(e.__traceback__, tb)

        e = IndexError(5).with_traceback(tb)
405
        self.assertIsInstance(e, IndexError)
406 407 408 409 410 411
        self.assertEqual(e.__traceback__, tb)

        class MyException(Exception):
            pass

        e = MyException().with_traceback(tb)
412
        self.assertIsInstance(e, MyException)
413 414 415 416 417 418
        self.assertEqual(e.__traceback__, tb)

    def testInvalidTraceback(self):
        try:
            Exception().__traceback__ = 5
        except TypeError as e:
419
            self.assertIn("__traceback__ must be a traceback", str(e))
420 421 422
        else:
            self.fail("No exception raised")

423 424 425 426 427 428
    def testInvalidAttrs(self):
        self.assertRaises(TypeError, setattr, Exception(), '__cause__', 1)
        self.assertRaises(TypeError, delattr, Exception(), '__cause__')
        self.assertRaises(TypeError, setattr, Exception(), '__context__', 1)
        self.assertRaises(TypeError, delattr, Exception(), '__context__')

429 430 431 432 433 434 435 436 437 438 439 440 441
    def testNoneClearsTracebackAttr(self):
        try:
            raise IndexError(4)
        except:
            tb = sys.exc_info()[2]

        e = Exception()
        e.__traceback__ = tb
        e.__traceback__ = None
        self.assertEqual(e.__traceback__, None)

    def testChainingAttrs(self):
        e = Exception()
442
        self.assertIsNone(e.__context__)
443
        self.assertIsNone(e.__cause__)
444 445

        e = TypeError()
446
        self.assertIsNone(e.__context__)
447
        self.assertIsNone(e.__cause__)
448

449
        class MyException(OSError):
450 451 452
            pass

        e = MyException()
453
        self.assertIsNone(e.__context__)
454
        self.assertIsNone(e.__cause__)
455 456 457 458 459 460 461 462

    def testChainingDescriptors(self):
        try:
            raise Exception()
        except Exception as exc:
            e = exc

        self.assertIsNone(e.__context__)
463 464
        self.assertIsNone(e.__cause__)
        self.assertFalse(e.__suppress_context__)
465 466 467 468 469

        e.__context__ = NameError()
        e.__cause__ = None
        self.assertIsInstance(e.__context__, NameError)
        self.assertIsNone(e.__cause__)
470 471 472
        self.assertTrue(e.__suppress_context__)
        e.__suppress_context__ = False
        self.assertFalse(e.__suppress_context__)
473

474 475 476 477 478 479 480 481 482 483 484
    def testKeywordArgs(self):
        # test that builtin exception don't take keyword args,
        # but user-defined subclasses can if they want
        self.assertRaises(TypeError, BaseException, a=1)

        class DerivedException(BaseException):
            def __init__(self, fancy_arg):
                BaseException.__init__(self)
                self.fancy_arg = fancy_arg

        x = DerivedException(fancy_arg=42)
485
        self.assertEqual(x.fancy_arg, 42)
486

487
    @no_tracing
488 489 490
    def testInfiniteRecursion(self):
        def f():
            return f()
491
        self.assertRaises(RecursionError, f)
492 493 494 495 496 497

        def g():
            try:
                return g()
            except ValueError:
                return -1
498
        self.assertRaises(RecursionError, g)
499

500 501
    def test_str(self):
        # Make sure both instances and classes have a str representation.
502 503
        self.assertTrue(str(Exception))
        self.assertTrue(str(Exception('a')))
504
        self.assertTrue(str(Exception('a', 'b')))
505

506 507 508
    def testExceptionCleanupNames(self):
        # Make sure the local variable bound to the exception instance by
        # an "except" statement is only visible inside the except block.
509 510 511
        try:
            raise Exception()
        except Exception as e:
512
            self.assertTrue(e)
513
            del e
514
        self.assertNotIn('e', locals())
515

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    def testExceptionCleanupState(self):
        # Make sure exception state is cleaned up as soon as the except
        # block is left. See #2507

        class MyException(Exception):
            def __init__(self, obj):
                self.obj = obj
        class MyObj:
            pass

        def inner_raising_func():
            # Create some references in exception value and traceback
            local_ref = obj
            raise MyException(obj)

531
        # Qualified "except" with "as"
532 533 534 535 536 537 538 539
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            inner_raising_func()
        except MyException as e:
            pass
        obj = None
        obj = wr()
540
        self.assertTrue(obj is None, "%s" % obj)
541

542 543 544 545 546 547 548 549 550
        # Qualified "except" without "as"
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            inner_raising_func()
        except MyException:
            pass
        obj = None
        obj = wr()
551
        self.assertTrue(obj is None, "%s" % obj)
552 553 554 555 556 557 558 559 560 561

        # Bare "except"
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            inner_raising_func()
        except:
            pass
        obj = None
        obj = wr()
562
        self.assertTrue(obj is None, "%s" % obj)
563 564 565 566 567 568 569 570 571 572 573

        # "except" with premature block leave
        obj = MyObj()
        wr = weakref.ref(obj)
        for i in [0]:
            try:
                inner_raising_func()
            except:
                break
        obj = None
        obj = wr()
574
        self.assertTrue(obj is None, "%s" % obj)
575 576 577 578 579 580 581 582 583

        # "except" block raising another exception
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            try:
                inner_raising_func()
            except:
                raise KeyError
584 585 586 587 588 589
        except KeyError as e:
            # We want to test that the except block above got rid of
            # the exception raised in inner_raising_func(), but it
            # also ends up in the __context__ of the KeyError, so we
            # must clear the latter manually for our test to succeed.
            e.__context__ = None
590 591
            obj = None
            obj = wr()
592 593 594
            # guarantee no ref cycles on CPython (don't gc_collect)
            if check_impl_detail(cpython=False):
                gc_collect()
595
            self.assertTrue(obj is None, "%s" % obj)
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610

        # Some complicated construct
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            inner_raising_func()
        except MyException:
            try:
                try:
                    raise
                finally:
                    raise
            except MyException:
                pass
        obj = None
611 612
        if check_impl_detail(cpython=False):
            gc_collect()
613
        obj = wr()
614
        self.assertTrue(obj is None, "%s" % obj)
615 616 617 618 619 620 621 622 623 624 625 626

        # Inside an exception-silencing "with" block
        class Context:
            def __enter__(self):
                return self
            def __exit__ (self, exc_type, exc_value, exc_tb):
                return True
        obj = MyObj()
        wr = weakref.ref(obj)
        with Context():
            inner_raising_func()
        obj = None
627 628
        if check_impl_detail(cpython=False):
            gc_collect()
629
        obj = wr()
630
        self.assertTrue(obj is None, "%s" % obj)
631

632 633 634 635 636 637 638 639 640 641 642
    def test_exception_target_in_nested_scope(self):
        # issue 4617: This used to raise a SyntaxError
        # "can not delete variable 'e' referenced in nested scope"
        def print_error():
            e
        try:
            something
        except Exception as e:
            print_error()
            # implicit "del e" here

643 644 645 646 647 648 649 650 651 652 653
    def test_generator_leaking(self):
        # Test that generator exception state doesn't leak into the calling
        # frame
        def yield_raise():
            try:
                raise KeyError("caught")
            except KeyError:
                yield sys.exc_info()[0]
                yield sys.exc_info()[0]
            yield sys.exc_info()[0]
        g = yield_raise()
654 655 656 657 658
        self.assertEqual(next(g), KeyError)
        self.assertEqual(sys.exc_info()[0], None)
        self.assertEqual(next(g), KeyError)
        self.assertEqual(sys.exc_info()[0], None)
        self.assertEqual(next(g), None)
659 660 661 662 663 664

        # Same test, but inside an exception handler
        try:
            raise TypeError("foo")
        except TypeError:
            g = yield_raise()
665 666 667 668 669
            self.assertEqual(next(g), KeyError)
            self.assertEqual(sys.exc_info()[0], TypeError)
            self.assertEqual(next(g), KeyError)
            self.assertEqual(sys.exc_info()[0], TypeError)
            self.assertEqual(next(g), TypeError)
670
            del g
671
            self.assertEqual(sys.exc_info()[0], TypeError)
672

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
    def test_generator_leaking2(self):
        # See issue 12475.
        def g():
            yield
        try:
            raise RuntimeError
        except RuntimeError:
            it = g()
            next(it)
        try:
            next(it)
        except StopIteration:
            pass
        self.assertEqual(sys.exc_info(), (None, None, None))

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
    def test_generator_leaking3(self):
        # See issue #23353.  When gen.throw() is called, the caller's
        # exception state should be save and restored.
        def g():
            try:
                yield
            except ZeroDivisionError:
                yield sys.exc_info()[1]
        it = g()
        next(it)
        try:
            1/0
        except ZeroDivisionError as e:
            self.assertIs(sys.exc_info()[1], e)
            gen_exc = it.throw(e)
            self.assertIs(sys.exc_info()[1], e)
            self.assertIs(gen_exc, e)
        self.assertEqual(sys.exc_info(), (None, None, None))

    def test_generator_leaking4(self):
        # See issue #23353.  When an exception is raised by a generator,
        # the caller's exception state should still be restored.
        def g():
            try:
                1/0
            except ZeroDivisionError:
                yield sys.exc_info()[0]
                raise
        it = g()
        try:
            raise TypeError
        except TypeError:
            # The caller's exception state (TypeError) is temporarily
            # saved in the generator.
            tp = next(it)
        self.assertIs(tp, ZeroDivisionError)
        try:
            next(it)
            # We can't check it immediately, but while next() returns
            # with an exception, it shouldn't have restored the old
            # exception state (TypeError).
        except ZeroDivisionError as e:
            self.assertIs(sys.exc_info()[1], e)
        # We used to find TypeError here.
        self.assertEqual(sys.exc_info(), (None, None, None))

734 735 736 737 738 739 740 741 742 743 744 745
    def test_generator_doesnt_retain_old_exc(self):
        def g():
            self.assertIsInstance(sys.exc_info()[1], RuntimeError)
            yield
            self.assertEqual(sys.exc_info(), (None, None, None))
        it = g()
        try:
            raise RuntimeError
        except RuntimeError:
            next(it)
        self.assertRaises(StopIteration, next, it)

746 747 748 749 750 751 752 753 754 755 756 757 758 759
    def test_generator_finalizing_and_exc_info(self):
        # See #7173
        def simple_gen():
            yield 1
        def run_gen():
            gen = simple_gen()
            try:
                raise RuntimeError
            except RuntimeError:
                return next(gen)
        run_gen()
        gc_collect()
        self.assertEqual(sys.exc_info(), (None, None, None))

760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
    def _check_generator_cleanup_exc_state(self, testfunc):
        # Issue #12791: exception state is cleaned up as soon as a generator
        # is closed (reference cycles are broken).
        class MyException(Exception):
            def __init__(self, obj):
                self.obj = obj
        class MyObj:
            pass

        def raising_gen():
            try:
                raise MyException(obj)
            except MyException:
                yield

        obj = MyObj()
        wr = weakref.ref(obj)
        g = raising_gen()
        next(g)
        testfunc(g)
        g = obj = None
        obj = wr()
        self.assertIs(obj, None)

    def test_generator_throw_cleanup_exc_state(self):
        def do_throw(g):
            try:
                g.throw(RuntimeError())
            except RuntimeError:
                pass
        self._check_generator_cleanup_exc_state(do_throw)

    def test_generator_close_cleanup_exc_state(self):
        def do_close(g):
            g.close()
        self._check_generator_cleanup_exc_state(do_close)

    def test_generator_del_cleanup_exc_state(self):
        def do_del(g):
            g = None
        self._check_generator_cleanup_exc_state(do_del)

    def test_generator_next_cleanup_exc_state(self):
        def do_next(g):
            try:
                next(g)
            except StopIteration:
                pass
            else:
                self.fail("should have raised StopIteration")
        self._check_generator_cleanup_exc_state(do_next)

    def test_generator_send_cleanup_exc_state(self):
        def do_send(g):
            try:
                g.send(None)
            except StopIteration:
                pass
            else:
                self.fail("should have raised StopIteration")
        self._check_generator_cleanup_exc_state(do_send)

822 823 824
    def test_3114(self):
        # Bug #3114: in its destructor, MyObject retrieves a pointer to
        # obsolete and/or deallocated objects.
825 826 827 828 829 830 831 832 833
        class MyObject:
            def __del__(self):
                nonlocal e
                e = sys.exc_info()
        e = ()
        try:
            raise Exception(MyObject())
        except:
            pass
834
        self.assertEqual(e, (None, None, None))
835

836
    def test_unicode_change_attributes(self):
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
        # See issue 7309. This was a crasher.

        u = UnicodeEncodeError('baz', 'xxxxx', 1, 5, 'foo')
        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: foo")
        u.end = 2
        self.assertEqual(str(u), "'baz' codec can't encode character '\\x78' in position 1: foo")
        u.end = 5
        u.reason = 0x345345345345345345
        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: 965230951443685724997")
        u.encoding = 4000
        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1-4: 965230951443685724997")
        u.start = 1000
        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1000-4: 965230951443685724997")

        u = UnicodeDecodeError('baz', b'xxxxx', 1, 5, 'foo')
        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: foo")
        u.end = 2
        self.assertEqual(str(u), "'baz' codec can't decode byte 0x78 in position 1: foo")
        u.end = 5
        u.reason = 0x345345345345345345
        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: 965230951443685724997")
        u.encoding = 4000
        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1-4: 965230951443685724997")
        u.start = 1000
        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1000-4: 965230951443685724997")

        u = UnicodeTranslateError('xxxx', 1, 5, 'foo')
        self.assertEqual(str(u), "can't translate characters in position 1-4: foo")
        u.end = 2
        self.assertEqual(str(u), "can't translate character '\\x78' in position 1: foo")
        u.end = 5
        u.reason = 0x345345345345345345
        self.assertEqual(str(u), "can't translate characters in position 1-4: 965230951443685724997")
        u.start = 1000
        self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997")
872

873 874
    def test_unicode_errors_no_object(self):
        # See issue #21134.
875
        klasses = UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError
876 877 878
        for klass in klasses:
            self.assertEqual(str(klass.__new__(klass)), "")

879
    @no_tracing
880 881 882 883 884 885 886 887 888
    def test_badisinstance(self):
        # Bug #2542: if issubclass(e, MyException) raises an exception,
        # it should be ignored
        class Meta(type):
            def __subclasscheck__(cls, subclass):
                raise ValueError()
        class MyException(Exception, metaclass=Meta):
            pass

889
        with captured_stderr() as stderr:
890 891 892 893 894 895 896
            try:
                raise KeyError()
            except MyException as e:
                self.fail("exception should not be a MyException")
            except KeyError:
                pass
            except:
897
                self.fail("Should have raised KeyError")
898
            else:
899 900 901 902 903
                self.fail("Should have raised KeyError")

        def g():
            try:
                return g()
904
            except RecursionError:
905 906
                return sys.exc_info()
        e, v, tb = g()
907
        self.assertTrue(isinstance(v, RecursionError), type(v))
908
        self.assertIn("maximum recursion depth exceeded", str(v))
909

910

911
    @cpython_only
912 913 914 915
    def test_MemoryError(self):
        # PyErr_NoMemory always raises the same exception instance.
        # Check that the traceback is not doubled.
        import traceback
916
        from _testcapi import raise_memoryerror
917 918
        def raiseMemError():
            try:
919
                raise_memoryerror()
920 921 922 923 924 925 926 927 928 929
            except MemoryError as e:
                tb = e.__traceback__
            else:
                self.fail("Should have raises a MemoryError")
            return traceback.format_tb(tb)

        tb1 = raiseMemError()
        tb2 = raiseMemError()
        self.assertEqual(tb1, tb2)

930
    @cpython_only
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
    def test_exception_with_doc(self):
        import _testcapi
        doc2 = "This is a test docstring."
        doc4 = "This is another test docstring."

        self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
                          "error1")

        # test basic usage of PyErr_NewException
        error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
        self.assertIs(type(error1), type)
        self.assertTrue(issubclass(error1, Exception))
        self.assertIsNone(error1.__doc__)

        # test with given docstring
        error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
        self.assertEqual(error2.__doc__, doc2)

        # test with explicit base (without docstring)
        error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
                                                   base=error2)
        self.assertTrue(issubclass(error3, error2))

        # test with explicit base tuple
        class C(object):
            pass
        error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
                                                   (error3, C))
        self.assertTrue(issubclass(error4, error3))
        self.assertTrue(issubclass(error4, C))
        self.assertEqual(error4.__doc__, doc4)

        # test with explicit dictionary
        error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
                                                   error4, {'a': 1})
        self.assertTrue(issubclass(error5, error4))
        self.assertEqual(error5.a, 1)
        self.assertEqual(error5.__doc__, "")

970
    @cpython_only
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
    def test_memory_error_cleanup(self):
        # Issue #5437: preallocated MemoryError instances should not keep
        # traceback objects alive.
        from _testcapi import raise_memoryerror
        class C:
            pass
        wr = None
        def inner():
            nonlocal wr
            c = C()
            wr = weakref.ref(c)
            raise_memoryerror()
        # We cannot use assertRaises since it manually deletes the traceback
        try:
            inner()
        except MemoryError as e:
            self.assertNotEqual(wr(), None)
        else:
            self.fail("MemoryError not raised")
        self.assertEqual(wr(), None)

992
    @no_tracing
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
    def test_recursion_error_cleanup(self):
        # Same test as above, but with "recursion exceeded" errors
        class C:
            pass
        wr = None
        def inner():
            nonlocal wr
            c = C()
            wr = weakref.ref(c)
            inner()
        # We cannot use assertRaises since it manually deletes the traceback
        try:
            inner()
1006
        except RecursionError as e:
1007 1008
            self.assertNotEqual(wr(), None)
        else:
1009
            self.fail("RecursionError not raised")
1010
        self.assertEqual(wr(), None)
1011

1012 1013 1014 1015 1016 1017
    def test_errno_ENOTDIR(self):
        # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
        with self.assertRaises(OSError) as cm:
            os.listdir(__file__)
        self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception)

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
    def test_unraisable(self):
        # Issue #22836: PyErr_WriteUnraisable() should give sensible reports
        class BrokenDel:
            def __del__(self):
                exc = ValueError("del is broken")
                # The following line is included in the traceback report:
                raise exc

        class BrokenRepr(BrokenDel):
            def __repr__(self):
                raise AttributeError("repr() is broken")

        class BrokenExceptionDel:
            def __del__(self):
                exc = BrokenStrException()
                # The following line is included in the traceback report:
                raise exc

        for test_class in (BrokenDel, BrokenRepr, BrokenExceptionDel):
            with self.subTest(test_class):
                obj = test_class()
                with captured_stderr() as stderr:
                    del obj
                report = stderr.getvalue()
                self.assertIn("Exception ignored", report)
                if test_class is BrokenRepr:
                    self.assertIn("<object repr() failed>", report)
                else:
                    self.assertIn(test_class.__del__.__qualname__, report)
                self.assertIn("test_exceptions.py", report)
                self.assertIn("raise exc", report)
                if test_class is BrokenExceptionDel:
                    self.assertIn("BrokenStrException", report)
                    self.assertIn("<exception str() failed>", report)
                else:
                    self.assertIn("ValueError", report)
                    self.assertIn("del is broken", report)
                self.assertTrue(report.endswith("\n"))

    def test_unhandled(self):
        # Check for sensible reporting of unhandled exceptions
        for exc_type in (ValueError, BrokenStrException):
            with self.subTest(exc_type):
                try:
                    exc = exc_type("test message")
                    # The following line is included in the traceback report:
                    raise exc
                except exc_type:
                    with captured_stderr() as stderr:
                        sys.__excepthook__(*sys.exc_info())
                report = stderr.getvalue()
                self.assertIn("test_exceptions.py", report)
                self.assertIn("raise exc", report)
                self.assertIn(exc_type.__name__, report)
                if exc_type is BrokenStrException:
                    self.assertIn("<exception str() failed>", report)
                else:
                    self.assertIn("test message", report)
                self.assertTrue(report.endswith("\n"))

1078

1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
class ImportErrorTests(unittest.TestCase):

    def test_attributes(self):
        # Setting 'name' and 'path' should not be a problem.
        exc = ImportError('test')
        self.assertIsNone(exc.name)
        self.assertIsNone(exc.path)

        exc = ImportError('test', name='somemodule')
        self.assertEqual(exc.name, 'somemodule')
        self.assertIsNone(exc.path)

        exc = ImportError('test', path='somepath')
        self.assertEqual(exc.path, 'somepath')
        self.assertIsNone(exc.name)

        exc = ImportError('test', path='somepath', name='somename')
        self.assertEqual(exc.name, 'somename')
        self.assertEqual(exc.path, 'somepath')

1099 1100
    def test_non_str_argument(self):
        # Issue #15778
1101 1102 1103 1104
        with check_warnings(('', BytesWarning), quiet=True):
            arg = b'abc'
            exc = ImportError(arg)
            self.assertEqual(str(arg), str(exc))
1105 1106


1107
if __name__ == '__main__':
1108
    unittest.main()