test_exceptions.py 35.7 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_output, 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

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

25 26 27 28
class ExceptionTests(unittest.TestCase):

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

    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
51
                marshal.loads(b'')
52 53 54 55 56 57 58
            except EOFError:
                pass
        finally:
            sys.stdin = savestdin
            fp.close()
            unlink(TESTFN)

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

        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")

        self.raise_catch(SyntaxError, "SyntaxError")
89
        try: exec('/\n')
90 91 92 93 94
        except SyntaxError: pass

        self.raise_catch(IndentationError, "IndentationError")

        self.raise_catch(TabError, "TabError")
95 96 97 98
        try: compile("try:\n\t1/0\n    \t1/0\nfinally:\n pass\n",
                     '<string>', 'exec')
        except TabError: pass
        else: self.fail("TabError not raised")
99 100 101 102 103 104 105 106 107 108 109

        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")
110
        self.assertRaises(ValueError, chr, 17<<16)
111 112 113 114 115 116 117

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

        self.raise_catch(Exception, "Exception")
        try: x = 1/0
118
        except Exception as e: pass
119 120 121 122 123 124 125 126

    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')
127
            except SyntaxError as e:
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
                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")

151 152 153 154 155 156 157 158 159 160 161 162 163
    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)

164
    @cpython_only
165 166 167 168 169 170
    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_):
171
                raise RuntimeError("can't instantiate BadException")
172 173 174 175 176 177 178 179

        class InvalidException:
            pass

        def test_capi1():
            import _testcapi
            try:
                _testcapi.raise_exception(BadException, 1)
180
            except TypeError as err:
181 182
                exc, err, tb = sys.exc_info()
                co = tb.tb_frame.f_code
183
                self.assertEqual(co.co_name, "test_capi1")
184
                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
185 186 187 188 189 190 191
            else:
                self.fail("Expected exception")

        def test_capi2():
            import _testcapi
            try:
                _testcapi.raise_exception(BadException, 0)
192
            except RuntimeError as err:
193 194
                exc, err, tb = sys.exc_info()
                co = tb.tb_frame.f_code
195
                self.assertEqual(co.co_name, "__init__")
196
                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
197
                co2 = tb.tb_frame.f_back.f_code
198
                self.assertEqual(co2.co_name, "test_capi2")
199 200 201 202 203 204 205 206 207 208 209 210 211
            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()

212
    def test_WindowsError(self):
213
        try:
214 215 216 217
            WindowsError
        except NameError:
            pass
        else:
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
            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')
233
            self.assertEqual(str(w), "[WinError 3] foo: 'bar'")
234 235 236 237 238 239
            # 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)
240
            self.assertEqual(str(w), "[WinError 1001] foo")
241 242 243 244 245 246
            # 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)
247

248 249
    @unittest.skipUnless(sys.platform == 'win32',
                         'test specific to Windows')
250 251
    def test_windows_message(self):
        """Should fill in unknown error code in Windows error message"""
252 253 254 255 256
        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)
257

258 259
    def testAttributes(self):
        # test that exception attributes are happy
260 261

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

348 349 350 351
        for exc, args, expected in exceptionList:
            try:
                e = exc(*args)
            except:
352
                print("\nexc=%r, args=%r" % (exc, args), file=sys.stderr)
353 354 355
                raise
            else:
                # Verify module name
356 357
                if not type(e).__name__.endswith('NaiveException'):
                    self.assertEqual(type(e).__module__, 'builtins')
358 359 360 361
                # Verify no ref leaks in Exc_str()
                s = str(e)
                for checkArgName in expected:
                    value = getattr(e, checkArgName)
362 363 364 365 366
                    self.assertEqual(repr(value),
                                     repr(expected[checkArgName]),
                                     '%r.%s == %r, expected %r' % (
                                     e, checkArgName,
                                     value, expected[checkArgName]))
367 368

                # test for pickling support
369
                for p in [pickle]:
370 371 372 373 374 375
                    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])
376 377 378
                            self.assertEqual(got, want,
                                             'pickled "%r", attribute "%s' %
                                             (e, checkArgName))
379

380 381 382 383 384 385 386
    def testWithTraceback(self):
        try:
            raise IndexError(4)
        except:
            tb = sys.exc_info()[2]

        e = BaseException().with_traceback(tb)
387
        self.assertIsInstance(e, BaseException)
388 389 390
        self.assertEqual(e.__traceback__, tb)

        e = IndexError(5).with_traceback(tb)
391
        self.assertIsInstance(e, IndexError)
392 393 394 395 396 397
        self.assertEqual(e.__traceback__, tb)

        class MyException(Exception):
            pass

        e = MyException().with_traceback(tb)
398
        self.assertIsInstance(e, MyException)
399 400 401 402 403 404
        self.assertEqual(e.__traceback__, tb)

    def testInvalidTraceback(self):
        try:
            Exception().__traceback__ = 5
        except TypeError as e:
405
            self.assertIn("__traceback__ must be a traceback", str(e))
406 407 408
        else:
            self.fail("No exception raised")

409 410 411 412 413 414
    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__')

415 416 417 418 419 420 421 422 423 424 425 426 427
    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()
428
        self.assertIsNone(e.__context__)
429
        self.assertIsNone(e.__cause__)
430 431

        e = TypeError()
432
        self.assertIsNone(e.__context__)
433
        self.assertIsNone(e.__cause__)
434

435
        class MyException(OSError):
436 437 438
            pass

        e = MyException()
439
        self.assertIsNone(e.__context__)
440
        self.assertIsNone(e.__cause__)
441 442 443 444 445 446 447 448

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

        self.assertIsNone(e.__context__)
449 450
        self.assertIsNone(e.__cause__)
        self.assertFalse(e.__suppress_context__)
451 452 453 454 455

        e.__context__ = NameError()
        e.__cause__ = None
        self.assertIsInstance(e.__context__, NameError)
        self.assertIsNone(e.__cause__)
456 457 458
        self.assertTrue(e.__suppress_context__)
        e.__suppress_context__ = False
        self.assertFalse(e.__suppress_context__)
459

460 461 462 463 464 465 466 467 468 469 470
    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)
471
        self.assertEqual(x.fancy_arg, 42)
472

473
    @no_tracing
474 475 476 477 478 479 480 481 482 483 484 485
    def testInfiniteRecursion(self):
        def f():
            return f()
        self.assertRaises(RuntimeError, f)

        def g():
            try:
                return g()
            except ValueError:
                return -1
        self.assertRaises(RuntimeError, g)

486 487
    def test_str(self):
        # Make sure both instances and classes have a str representation.
488 489
        self.assertTrue(str(Exception))
        self.assertTrue(str(Exception('a')))
490
        self.assertTrue(str(Exception('a', 'b')))
491

492 493 494
    def testExceptionCleanupNames(self):
        # Make sure the local variable bound to the exception instance by
        # an "except" statement is only visible inside the except block.
495 496 497
        try:
            raise Exception()
        except Exception as e:
498
            self.assertTrue(e)
499
            del e
500
        self.assertNotIn('e', locals())
501

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
    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)

517
        # Qualified "except" with "as"
518 519 520 521 522 523 524 525
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            inner_raising_func()
        except MyException as e:
            pass
        obj = None
        obj = wr()
526
        self.assertTrue(obj is None, "%s" % obj)
527

528 529 530 531 532 533 534 535 536
        # Qualified "except" without "as"
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            inner_raising_func()
        except MyException:
            pass
        obj = None
        obj = wr()
537
        self.assertTrue(obj is None, "%s" % obj)
538 539 540 541 542 543 544 545 546 547

        # Bare "except"
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            inner_raising_func()
        except:
            pass
        obj = None
        obj = wr()
548
        self.assertTrue(obj is None, "%s" % obj)
549 550 551 552 553 554 555 556 557 558 559

        # "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()
560
        self.assertTrue(obj is None, "%s" % obj)
561 562 563 564 565 566 567 568 569

        # "except" block raising another exception
        obj = MyObj()
        wr = weakref.ref(obj)
        try:
            try:
                inner_raising_func()
            except:
                raise KeyError
570 571 572 573 574 575
        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
576 577
            obj = None
            obj = wr()
578 579 580
            # guarantee no ref cycles on CPython (don't gc_collect)
            if check_impl_detail(cpython=False):
                gc_collect()
581
            self.assertTrue(obj is None, "%s" % obj)
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596

        # 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
597 598
        if check_impl_detail(cpython=False):
            gc_collect()
599
        obj = wr()
600
        self.assertTrue(obj is None, "%s" % obj)
601 602 603 604 605 606 607 608 609 610 611 612

        # 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
613 614
        if check_impl_detail(cpython=False):
            gc_collect()
615
        obj = wr()
616
        self.assertTrue(obj is None, "%s" % obj)
617

618 619 620 621 622 623 624 625 626 627 628
    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

629 630 631 632 633 634 635 636 637 638 639
    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()
640 641 642 643 644
        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)
645 646 647 648 649 650

        # Same test, but inside an exception handler
        try:
            raise TypeError("foo")
        except TypeError:
            g = yield_raise()
651 652 653 654 655
            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)
656
            del g
657
            self.assertEqual(sys.exc_info()[0], TypeError)
658

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
    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))

674 675 676 677 678 679 680 681 682 683 684 685 686 687 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
    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))

720 721 722 723 724 725 726 727 728 729 730 731
    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)

732 733 734 735 736 737 738 739 740 741 742 743 744 745
    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))

746 747 748 749 750 751 752 753 754 755 756 757 758 759 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
    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)

808 809 810
    def test_3114(self):
        # Bug #3114: in its destructor, MyObject retrieves a pointer to
        # obsolete and/or deallocated objects.
811 812 813 814 815 816 817 818 819
        class MyObject:
            def __del__(self):
                nonlocal e
                e = sys.exc_info()
        e = ()
        try:
            raise Exception(MyObject())
        except:
            pass
820
        self.assertEqual(e, (None, None, None))
821

822
    def test_unicode_change_attributes(self):
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
        # 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")
858

859 860
    def test_unicode_errors_no_object(self):
        # See issue #21134.
861
        klasses = UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError
862 863 864
        for klass in klasses:
            self.assertEqual(str(klass.__new__(klass)), "")

865
    @no_tracing
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882
    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

        with captured_output("stderr") as stderr:
            try:
                raise KeyError()
            except MyException as e:
                self.fail("exception should not be a MyException")
            except KeyError:
                pass
            except:
883
                self.fail("Should have raised KeyError")
884
            else:
885 886 887 888 889 890 891 892
                self.fail("Should have raised KeyError")

        def g():
            try:
                return g()
            except RuntimeError:
                return sys.exc_info()
        e, v, tb = g()
893
        self.assertTrue(isinstance(v, RuntimeError), type(v))
894
        self.assertIn("maximum recursion depth exceeded", str(v))
895

896

897
    @cpython_only
898 899 900 901
    def test_MemoryError(self):
        # PyErr_NoMemory always raises the same exception instance.
        # Check that the traceback is not doubled.
        import traceback
902
        from _testcapi import raise_memoryerror
903 904
        def raiseMemError():
            try:
905
                raise_memoryerror()
906 907 908 909 910 911 912 913 914 915
            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)

916
    @cpython_only
917 918 919 920 921 922 923 924 925 926 927 928 929 930 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
    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__, "")

956
    @cpython_only
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
    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)

978
    @no_tracing
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
    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()
        except RuntimeError as e:
            self.assertNotEqual(wr(), None)
        else:
            self.fail("RuntimeError not raised")
        self.assertEqual(wr(), None)
997

998 999 1000 1001 1002 1003 1004
    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)


1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
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')

1025 1026
    def test_non_str_argument(self):
        # Issue #15778
1027 1028 1029 1030
        with check_warnings(('', BytesWarning), quiet=True):
            arg = b'abc'
            exc = ImportError(arg)
            self.assertEqual(str(arg), str(exc))
1031 1032


1033
if __name__ == '__main__':
1034
    unittest.main()