1# Python test set -- part 5, built-in exceptions
2
3import os
4import sys
5import unittest
6import pickle
7import weakref
8import errno
9
10from test.support import (TESTFN, captured_stderr, check_impl_detail,
11                          check_warnings, cpython_only, gc_collect, run_unittest,
12                          no_tracing, unlink, import_module)
13
14class NaiveException(Exception):
15    def __init__(self, x):
16        self.x = x
17
18class SlottedNaiveException(Exception):
19    __slots__ = ('x',)
20    def __init__(self, x):
21        self.x = x
22
23class BrokenStrException(Exception):
24    def __str__(self):
25        raise Exception("str() is broken")
26
27# XXX This is not really enough, each *operation* should be tested!
28
29class ExceptionTests(unittest.TestCase):
30
31    def raise_catch(self, exc, excname):
32        try:
33            raise exc("spam")
34        except exc as err:
35            buf1 = str(err)
36        try:
37            raise exc("spam")
38        except exc as 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                import marshal
55                marshal.loads(b'')
56            except EOFError:
57                pass
58        finally:
59            sys.stdin = savestdin
60            fp.close()
61            unlink(TESTFN)
62
63        self.raise_catch(OSError, "OSError")
64        self.assertRaises(OSError, 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        self.raise_catch(RecursionError, "RecursionError")
92
93        self.raise_catch(SyntaxError, "SyntaxError")
94        try: exec('/\n')
95        except SyntaxError: pass
96
97        self.raise_catch(IndentationError, "IndentationError")
98
99        self.raise_catch(TabError, "TabError")
100        try: compile("try:\n\t1/0\n    \t1/0\nfinally:\n pass\n",
101                     '<string>', 'exec')
102        except TabError: pass
103        else: self.fail("TabError not raised")
104
105        self.raise_catch(SystemError, "SystemError")
106
107        self.raise_catch(SystemExit, "SystemExit")
108        self.assertRaises(SystemExit, sys.exit, 0)
109
110        self.raise_catch(TypeError, "TypeError")
111        try: [] + ()
112        except TypeError: pass
113
114        self.raise_catch(ValueError, "ValueError")
115        self.assertRaises(ValueError, chr, 17<<16)
116
117        self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
118        try: x = 1/0
119        except ZeroDivisionError: pass
120
121        self.raise_catch(Exception, "Exception")
122        try: x = 1/0
123        except Exception as e: pass
124
125        self.raise_catch(StopAsyncIteration, "StopAsyncIteration")
126
127    def testSyntaxErrorMessage(self):
128        # make sure the right exception message is raised for each of
129        # these code fragments
130
131        def ckmsg(src, msg):
132            try:
133                compile(src, '<fragment>', 'exec')
134            except SyntaxError as e:
135                if e.msg != msg:
136                    self.fail("expected %s, got %s" % (msg, e.msg))
137            else:
138                self.fail("failed to get expected SyntaxError")
139
140        s = '''while 1:
141            try:
142                pass
143            finally:
144                continue'''
145
146        if not sys.platform.startswith('java'):
147            ckmsg(s, "'continue' not supported inside 'finally' clause")
148
149        s = '''if 1:
150        try:
151            continue
152        except:
153            pass'''
154
155        ckmsg(s, "'continue' not properly in loop")
156        ckmsg("continue\n", "'continue' not properly in loop")
157
158    def testSyntaxErrorOffset(self):
159        def check(src, lineno, offset):
160            with self.assertRaises(SyntaxError) as cm:
161                compile(src, '<fragment>', 'exec')
162            self.assertEqual(cm.exception.lineno, lineno)
163            self.assertEqual(cm.exception.offset, offset)
164
165        check('def fact(x):\n\treturn x!\n', 2, 10)
166        check('1 +\n', 1, 4)
167        check('def spam():\n  print(1)\n print(2)', 3, 10)
168        check('Python = "Python" +', 1, 20)
169        check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20)
170
171    @cpython_only
172    def testSettingException(self):
173        # test that setting an exception at the C level works even if the
174        # exception object can't be constructed.
175
176        class BadException(Exception):
177            def __init__(self_):
178                raise RuntimeError("can't instantiate BadException")
179
180        class InvalidException:
181            pass
182
183        def test_capi1():
184            import _testcapi
185            try:
186                _testcapi.raise_exception(BadException, 1)
187            except TypeError as err:
188                exc, err, tb = sys.exc_info()
189                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            else:
193                self.fail("Expected exception")
194
195        def test_capi2():
196            import _testcapi
197            try:
198                _testcapi.raise_exception(BadException, 0)
199            except RuntimeError as err:
200                exc, err, tb = sys.exc_info()
201                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            else:
207                self.fail("Expected exception")
208
209        def test_capi3():
210            import _testcapi
211            self.assertRaises(SystemError, _testcapi.raise_exception,
212                              InvalidException, 1)
213
214        if not sys.platform.startswith('java'):
215            test_capi1()
216            test_capi2()
217            test_capi3()
218
219    def test_WindowsError(self):
220        try:
221            WindowsError
222        except NameError:
223            pass
224        else:
225            self.assertIs(WindowsError, OSError)
226            self.assertEqual(str(OSError(1001)), "1001")
227            self.assertEqual(str(OSError(1001, "message")),
228                             "[Errno 1001] message")
229            # POSIX errno (9 aka EBADF) is untranslated
230            w = OSError(9, 'foo', 'bar')
231            self.assertEqual(w.errno, 9)
232            self.assertEqual(w.winerror, None)
233            self.assertEqual(str(w), "[Errno 9] foo: 'bar'")
234            # ERROR_PATH_NOT_FOUND (win error 3) becomes ENOENT (2)
235            w = OSError(0, 'foo', 'bar', 3)
236            self.assertEqual(w.errno, 2)
237            self.assertEqual(w.winerror, 3)
238            self.assertEqual(w.strerror, 'foo')
239            self.assertEqual(w.filename, 'bar')
240            self.assertEqual(w.filename2, None)
241            self.assertEqual(str(w), "[WinError 3] foo: 'bar'")
242            # Unknown win error becomes EINVAL (22)
243            w = OSError(0, 'foo', None, 1001)
244            self.assertEqual(w.errno, 22)
245            self.assertEqual(w.winerror, 1001)
246            self.assertEqual(w.strerror, 'foo')
247            self.assertEqual(w.filename, None)
248            self.assertEqual(w.filename2, None)
249            self.assertEqual(str(w), "[WinError 1001] foo")
250            # Non-numeric "errno"
251            w = OSError('bar', 'foo')
252            self.assertEqual(w.errno, 'bar')
253            self.assertEqual(w.winerror, None)
254            self.assertEqual(w.strerror, 'foo')
255            self.assertEqual(w.filename, None)
256            self.assertEqual(w.filename2, None)
257
258    @unittest.skipUnless(sys.platform == 'win32',
259                         'test specific to Windows')
260    def test_windows_message(self):
261        """Should fill in unknown error code in Windows error message"""
262        ctypes = import_module('ctypes')
263        # this error code has no message, Python formats it as hexadecimal
264        code = 3765269347
265        with self.assertRaisesRegex(OSError, 'Windows Error 0x%x' % code):
266            ctypes.pythonapi.PyErr_SetFromWindowsErr(code)
267
268    def testAttributes(self):
269        # test that exception attributes are happy
270
271        exceptionList = [
272            (BaseException, (), {'args' : ()}),
273            (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                {'args' : ('foo', 'bar'),
285                 'filename' : None, 'filename2' : None,
286                 'errno' : 'foo', 'strerror' : 'bar'}),
287            (OSError, ('foo', 'bar', 'baz'),
288                {'args' : ('foo', 'bar'),
289                 'filename' : 'baz', 'filename2' : None,
290                 'errno' : 'foo', 'strerror' : 'bar'}),
291            (OSError, ('foo', 'bar', 'baz', None, 'quux'),
292                {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}),
293            (OSError, ('errnoStr', 'strErrorStr', 'filenameStr'),
294                {'args' : ('errnoStr', 'strErrorStr'),
295                 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
296                 'filename' : 'filenameStr'}),
297            (OSError, (1, 'strErrorStr', 'filenameStr'),
298                {'args' : (1, 'strErrorStr'), 'errno' : 1,
299                 'strerror' : 'strErrorStr',
300                 'filename' : 'filenameStr', 'filename2' : None}),
301            (SyntaxError, (), {'msg' : None, 'text' : None,
302                'filename' : None, 'lineno' : None, 'offset' : None,
303                'print_file_and_line' : None}),
304            (SyntaxError, ('msgStr',),
305                {'args' : ('msgStr',), 'text' : None,
306                 'print_file_and_line' : None, 'msg' : 'msgStr',
307                 'filename' : None, 'lineno' : None, 'offset' : None}),
308            (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
309                           'textStr')),
310                {'offset' : 'offsetStr', 'text' : 'textStr',
311                 'args' : ('msgStr', ('filenameStr', 'linenoStr',
312                                      'offsetStr', 'textStr')),
313                 'print_file_and_line' : None, 'msg' : 'msgStr',
314                 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
315            (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
316                           'textStr', 'print_file_and_lineStr'),
317                {'text' : None,
318                 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
319                           'textStr', 'print_file_and_lineStr'),
320                 'print_file_and_line' : None, 'msg' : 'msgStr',
321                 'filename' : None, 'lineno' : None, 'offset' : None}),
322            (UnicodeError, (), {'args' : (),}),
323            (UnicodeEncodeError, ('ascii', 'a', 0, 1,
324                                  '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                                           'ordinal not in range'),
333                 'encoding' : 'ascii', 'object' : b'\xff',
334                 'start' : 0, 'reason' : 'ordinal not in range'}),
335            (UnicodeDecodeError, ('ascii', b'\xff', 0, 1,
336                                  '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            (NaiveException, ('foo',),
346                {'args': ('foo',), 'x': 'foo'}),
347            (SlottedNaiveException, ('foo',),
348                {'args': ('foo',), 'x': 'foo'}),
349        ]
350        try:
351            # More tests are in test_WindowsError
352            exceptionList.append(
353                (WindowsError, (1, 'strErrorStr', 'filenameStr'),
354                    {'args' : (1, 'strErrorStr'),
355                     'strerror' : 'strErrorStr', 'winerror' : None,
356                     'errno' : 1,
357                     'filename' : 'filenameStr', 'filename2' : None})
358            )
359        except NameError:
360            pass
361
362        for exc, args, expected in exceptionList:
363            try:
364                e = exc(*args)
365            except:
366                print("\nexc=%r, args=%r" % (exc, args), file=sys.stderr)
367                raise
368            else:
369                # Verify module name
370                if not type(e).__name__.endswith('NaiveException'):
371                    self.assertEqual(type(e).__module__, 'builtins')
372                # Verify no ref leaks in Exc_str()
373                s = str(e)
374                for checkArgName in expected:
375                    value = getattr(e, checkArgName)
376                    self.assertEqual(repr(value),
377                                     repr(expected[checkArgName]),
378                                     '%r.%s == %r, expected %r' % (
379                                     e, checkArgName,
380                                     value, expected[checkArgName]))
381
382                # test for pickling support
383                for p in [pickle]:
384                    for protocol in range(p.HIGHEST_PROTOCOL + 1):
385                        s = p.dumps(e, protocol)
386                        new = p.loads(s)
387                        for checkArgName in expected:
388                            got = repr(getattr(new, checkArgName))
389                            want = repr(expected[checkArgName])
390                            self.assertEqual(got, want,
391                                             'pickled "%r", attribute "%s' %
392                                             (e, checkArgName))
393
394    def testWithTraceback(self):
395        try:
396            raise IndexError(4)
397        except:
398            tb = sys.exc_info()[2]
399
400        e = BaseException().with_traceback(tb)
401        self.assertIsInstance(e, BaseException)
402        self.assertEqual(e.__traceback__, tb)
403
404        e = IndexError(5).with_traceback(tb)
405        self.assertIsInstance(e, IndexError)
406        self.assertEqual(e.__traceback__, tb)
407
408        class MyException(Exception):
409            pass
410
411        e = MyException().with_traceback(tb)
412        self.assertIsInstance(e, MyException)
413        self.assertEqual(e.__traceback__, tb)
414
415    def testInvalidTraceback(self):
416        try:
417            Exception().__traceback__ = 5
418        except TypeError as e:
419            self.assertIn("__traceback__ must be a traceback", str(e))
420        else:
421            self.fail("No exception raised")
422
423    def testInvalidAttrs(self):
424        self.assertRaises(TypeError, setattr, Exception(), '__cause__', 1)
425        self.assertRaises(TypeError, delattr, Exception(), '__cause__')
426        self.assertRaises(TypeError, setattr, Exception(), '__context__', 1)
427        self.assertRaises(TypeError, delattr, Exception(), '__context__')
428
429    def testNoneClearsTracebackAttr(self):
430        try:
431            raise IndexError(4)
432        except:
433            tb = sys.exc_info()[2]
434
435        e = Exception()
436        e.__traceback__ = tb
437        e.__traceback__ = None
438        self.assertEqual(e.__traceback__, None)
439
440    def testChainingAttrs(self):
441        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            pass
451
452        e = MyException()
453        self.assertIsNone(e.__context__)
454        self.assertIsNone(e.__cause__)
455
456    def testChainingDescriptors(self):
457        try:
458            raise Exception()
459        except Exception as exc:
460            e = exc
461
462        self.assertIsNone(e.__context__)
463        self.assertIsNone(e.__cause__)
464        self.assertFalse(e.__suppress_context__)
465
466        e.__context__ = NameError()
467        e.__cause__ = None
468        self.assertIsInstance(e.__context__, NameError)
469        self.assertIsNone(e.__cause__)
470        self.assertTrue(e.__suppress_context__)
471        e.__suppress_context__ = False
472        self.assertFalse(e.__suppress_context__)
473
474    def testKeywordArgs(self):
475        # test that builtin exception don't take keyword args,
476        # but user-defined subclasses can if they want
477        self.assertRaises(TypeError, BaseException, a=1)
478
479        class DerivedException(BaseException):
480            def __init__(self, fancy_arg):
481                BaseException.__init__(self)
482                self.fancy_arg = fancy_arg
483
484        x = DerivedException(fancy_arg=42)
485        self.assertEqual(x.fancy_arg, 42)
486
487    @no_tracing
488    def testInfiniteRecursion(self):
489        def f():
490            return f()
491        self.assertRaises(RecursionError, f)
492
493        def g():
494            try:
495                return g()
496            except ValueError:
497                return -1
498        self.assertRaises(RecursionError, g)
499
500    def test_str(self):
501        # Make sure both instances and classes have a str representation.
502        self.assertTrue(str(Exception))
503        self.assertTrue(str(Exception('a')))
504        self.assertTrue(str(Exception('a', 'b')))
505
506    def testExceptionCleanupNames(self):
507        # Make sure the local variable bound to the exception instance by
508        # an "except" statement is only visible inside the except block.
509        try:
510            raise Exception()
511        except Exception as e:
512            self.assertTrue(e)
513            del e
514        self.assertNotIn('e', locals())
515
516    def testExceptionCleanupState(self):
517        # Make sure exception state is cleaned up as soon as the except
518        # block is left. See #2507
519
520        class MyException(Exception):
521            def __init__(self, obj):
522                self.obj = obj
523        class MyObj:
524            pass
525
526        def inner_raising_func():
527            # Create some references in exception value and traceback
528            local_ref = obj
529            raise MyException(obj)
530
531        # Qualified "except" with "as"
532        obj = MyObj()
533        wr = weakref.ref(obj)
534        try:
535            inner_raising_func()
536        except MyException as e:
537            pass
538        obj = None
539        obj = wr()
540        self.assertTrue(obj is None, "%s" % obj)
541
542        # Qualified "except" without "as"
543        obj = MyObj()
544        wr = weakref.ref(obj)
545        try:
546            inner_raising_func()
547        except MyException:
548            pass
549        obj = None
550        obj = wr()
551        self.assertTrue(obj is None, "%s" % obj)
552
553        # Bare "except"
554        obj = MyObj()
555        wr = weakref.ref(obj)
556        try:
557            inner_raising_func()
558        except:
559            pass
560        obj = None
561        obj = wr()
562        self.assertTrue(obj is None, "%s" % obj)
563
564        # "except" with premature block leave
565        obj = MyObj()
566        wr = weakref.ref(obj)
567        for i in [0]:
568            try:
569                inner_raising_func()
570            except:
571                break
572        obj = None
573        obj = wr()
574        self.assertTrue(obj is None, "%s" % obj)
575
576        # "except" block raising another exception
577        obj = MyObj()
578        wr = weakref.ref(obj)
579        try:
580            try:
581                inner_raising_func()
582            except:
583                raise KeyError
584        except KeyError as e:
585            # We want to test that the except block above got rid of
586            # the exception raised in inner_raising_func(), but it
587            # also ends up in the __context__ of the KeyError, so we
588            # must clear the latter manually for our test to succeed.
589            e.__context__ = None
590            obj = None
591            obj = wr()
592            # guarantee no ref cycles on CPython (don't gc_collect)
593            if check_impl_detail(cpython=False):
594                gc_collect()
595            self.assertTrue(obj is None, "%s" % obj)
596
597        # Some complicated construct
598        obj = MyObj()
599        wr = weakref.ref(obj)
600        try:
601            inner_raising_func()
602        except MyException:
603            try:
604                try:
605                    raise
606                finally:
607                    raise
608            except MyException:
609                pass
610        obj = None
611        if check_impl_detail(cpython=False):
612            gc_collect()
613        obj = wr()
614        self.assertTrue(obj is None, "%s" % obj)
615
616        # Inside an exception-silencing "with" block
617        class Context:
618            def __enter__(self):
619                return self
620            def __exit__ (self, exc_type, exc_value, exc_tb):
621                return True
622        obj = MyObj()
623        wr = weakref.ref(obj)
624        with Context():
625            inner_raising_func()
626        obj = None
627        if check_impl_detail(cpython=False):
628            gc_collect()
629        obj = wr()
630        self.assertTrue(obj is None, "%s" % obj)
631
632    def test_exception_target_in_nested_scope(self):
633        # issue 4617: This used to raise a SyntaxError
634        # "can not delete variable 'e' referenced in nested scope"
635        def print_error():
636            e
637        try:
638            something
639        except Exception as e:
640            print_error()
641            # implicit "del e" here
642
643    def test_generator_leaking(self):
644        # Test that generator exception state doesn't leak into the calling
645        # frame
646        def yield_raise():
647            try:
648                raise KeyError("caught")
649            except KeyError:
650                yield sys.exc_info()[0]
651                yield sys.exc_info()[0]
652            yield sys.exc_info()[0]
653        g = yield_raise()
654        self.assertEqual(next(g), KeyError)
655        self.assertEqual(sys.exc_info()[0], None)
656        self.assertEqual(next(g), KeyError)
657        self.assertEqual(sys.exc_info()[0], None)
658        self.assertEqual(next(g), None)
659
660        # Same test, but inside an exception handler
661        try:
662            raise TypeError("foo")
663        except TypeError:
664            g = yield_raise()
665            self.assertEqual(next(g), KeyError)
666            self.assertEqual(sys.exc_info()[0], TypeError)
667            self.assertEqual(next(g), KeyError)
668            self.assertEqual(sys.exc_info()[0], TypeError)
669            self.assertEqual(next(g), TypeError)
670            del g
671            self.assertEqual(sys.exc_info()[0], TypeError)
672
673    def test_generator_leaking2(self):
674        # See issue 12475.
675        def g():
676            yield
677        try:
678            raise RuntimeError
679        except RuntimeError:
680            it = g()
681            next(it)
682        try:
683            next(it)
684        except StopIteration:
685            pass
686        self.assertEqual(sys.exc_info(), (None, None, None))
687
688    def test_generator_leaking3(self):
689        # See issue #23353.  When gen.throw() is called, the caller's
690        # exception state should be save and restored.
691        def g():
692            try:
693                yield
694            except ZeroDivisionError:
695                yield sys.exc_info()[1]
696        it = g()
697        next(it)
698        try:
699            1/0
700        except ZeroDivisionError as e:
701            self.assertIs(sys.exc_info()[1], e)
702            gen_exc = it.throw(e)
703            self.assertIs(sys.exc_info()[1], e)
704            self.assertIs(gen_exc, e)
705        self.assertEqual(sys.exc_info(), (None, None, None))
706
707    def test_generator_leaking4(self):
708        # See issue #23353.  When an exception is raised by a generator,
709        # the caller's exception state should still be restored.
710        def g():
711            try:
712                1/0
713            except ZeroDivisionError:
714                yield sys.exc_info()[0]
715                raise
716        it = g()
717        try:
718            raise TypeError
719        except TypeError:
720            # The caller's exception state (TypeError) is temporarily
721            # saved in the generator.
722            tp = next(it)
723        self.assertIs(tp, ZeroDivisionError)
724        try:
725            next(it)
726            # We can't check it immediately, but while next() returns
727            # with an exception, it shouldn't have restored the old
728            # exception state (TypeError).
729        except ZeroDivisionError as e:
730            self.assertIs(sys.exc_info()[1], e)
731        # We used to find TypeError here.
732        self.assertEqual(sys.exc_info(), (None, None, None))
733
734    def test_generator_doesnt_retain_old_exc(self):
735        def g():
736            self.assertIsInstance(sys.exc_info()[1], RuntimeError)
737            yield
738            self.assertEqual(sys.exc_info(), (None, None, None))
739        it = g()
740        try:
741            raise RuntimeError
742        except RuntimeError:
743            next(it)
744        self.assertRaises(StopIteration, next, it)
745
746    def test_generator_finalizing_and_exc_info(self):
747        # See #7173
748        def simple_gen():
749            yield 1
750        def run_gen():
751            gen = simple_gen()
752            try:
753                raise RuntimeError
754            except RuntimeError:
755                return next(gen)
756        run_gen()
757        gc_collect()
758        self.assertEqual(sys.exc_info(), (None, None, None))
759
760    def _check_generator_cleanup_exc_state(self, testfunc):
761        # Issue #12791: exception state is cleaned up as soon as a generator
762        # is closed (reference cycles are broken).
763        class MyException(Exception):
764            def __init__(self, obj):
765                self.obj = obj
766        class MyObj:
767            pass
768
769        def raising_gen():
770            try:
771                raise MyException(obj)
772            except MyException:
773                yield
774
775        obj = MyObj()
776        wr = weakref.ref(obj)
777        g = raising_gen()
778        next(g)
779        testfunc(g)
780        g = obj = None
781        obj = wr()
782        self.assertIs(obj, None)
783
784    def test_generator_throw_cleanup_exc_state(self):
785        def do_throw(g):
786            try:
787                g.throw(RuntimeError())
788            except RuntimeError:
789                pass
790        self._check_generator_cleanup_exc_state(do_throw)
791
792    def test_generator_close_cleanup_exc_state(self):
793        def do_close(g):
794            g.close()
795        self._check_generator_cleanup_exc_state(do_close)
796
797    def test_generator_del_cleanup_exc_state(self):
798        def do_del(g):
799            g = None
800        self._check_generator_cleanup_exc_state(do_del)
801
802    def test_generator_next_cleanup_exc_state(self):
803        def do_next(g):
804            try:
805                next(g)
806            except StopIteration:
807                pass
808            else:
809                self.fail("should have raised StopIteration")
810        self._check_generator_cleanup_exc_state(do_next)
811
812    def test_generator_send_cleanup_exc_state(self):
813        def do_send(g):
814            try:
815                g.send(None)
816            except StopIteration:
817                pass
818            else:
819                self.fail("should have raised StopIteration")
820        self._check_generator_cleanup_exc_state(do_send)
821
822    def test_3114(self):
823        # Bug #3114: in its destructor, MyObject retrieves a pointer to
824        # obsolete and/or deallocated objects.
825        class MyObject:
826            def __del__(self):
827                nonlocal e
828                e = sys.exc_info()
829        e = ()
830        try:
831            raise Exception(MyObject())
832        except:
833            pass
834        self.assertEqual(e, (None, None, None))
835
836    def test_unicode_change_attributes(self):
837        # See issue 7309. This was a crasher.
838
839        u = UnicodeEncodeError('baz', 'xxxxx', 1, 5, 'foo')
840        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: foo")
841        u.end = 2
842        self.assertEqual(str(u), "'baz' codec can't encode character '\\x78' in position 1: foo")
843        u.end = 5
844        u.reason = 0x345345345345345345
845        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: 965230951443685724997")
846        u.encoding = 4000
847        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1-4: 965230951443685724997")
848        u.start = 1000
849        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1000-4: 965230951443685724997")
850
851        u = UnicodeDecodeError('baz', b'xxxxx', 1, 5, 'foo')
852        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: foo")
853        u.end = 2
854        self.assertEqual(str(u), "'baz' codec can't decode byte 0x78 in position 1: foo")
855        u.end = 5
856        u.reason = 0x345345345345345345
857        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: 965230951443685724997")
858        u.encoding = 4000
859        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1-4: 965230951443685724997")
860        u.start = 1000
861        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1000-4: 965230951443685724997")
862
863        u = UnicodeTranslateError('xxxx', 1, 5, 'foo')
864        self.assertEqual(str(u), "can't translate characters in position 1-4: foo")
865        u.end = 2
866        self.assertEqual(str(u), "can't translate character '\\x78' in position 1: foo")
867        u.end = 5
868        u.reason = 0x345345345345345345
869        self.assertEqual(str(u), "can't translate characters in position 1-4: 965230951443685724997")
870        u.start = 1000
871        self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997")
872
873    def test_unicode_errors_no_object(self):
874        # See issue #21134.
875        klasses = UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError
876        for klass in klasses:
877            self.assertEqual(str(klass.__new__(klass)), "")
878
879    @no_tracing
880    def test_badisinstance(self):
881        # Bug #2542: if issubclass(e, MyException) raises an exception,
882        # it should be ignored
883        class Meta(type):
884            def __subclasscheck__(cls, subclass):
885                raise ValueError()
886        class MyException(Exception, metaclass=Meta):
887            pass
888
889        with captured_stderr() as stderr:
890            try:
891                raise KeyError()
892            except MyException as e:
893                self.fail("exception should not be a MyException")
894            except KeyError:
895                pass
896            except:
897                self.fail("Should have raised KeyError")
898            else:
899                self.fail("Should have raised KeyError")
900
901        def g():
902            try:
903                return g()
904            except RecursionError:
905                return sys.exc_info()
906        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    def test_MemoryError(self):
913        # PyErr_NoMemory always raises the same exception instance.
914        # Check that the traceback is not doubled.
915        import traceback
916        from _testcapi import raise_memoryerror
917        def raiseMemError():
918            try:
919                raise_memoryerror()
920            except MemoryError as e:
921                tb = e.__traceback__
922            else:
923                self.fail("Should have raises a MemoryError")
924            return traceback.format_tb(tb)
925
926        tb1 = raiseMemError()
927        tb2 = raiseMemError()
928        self.assertEqual(tb1, tb2)
929
930    @cpython_only
931    def test_exception_with_doc(self):
932        import _testcapi
933        doc2 = "This is a test docstring."
934        doc4 = "This is another test docstring."
935
936        self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
937                          "error1")
938
939        # test basic usage of PyErr_NewException
940        error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
941        self.assertIs(type(error1), type)
942        self.assertTrue(issubclass(error1, Exception))
943        self.assertIsNone(error1.__doc__)
944
945        # test with given docstring
946        error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
947        self.assertEqual(error2.__doc__, doc2)
948
949        # test with explicit base (without docstring)
950        error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
951                                                   base=error2)
952        self.assertTrue(issubclass(error3, error2))
953
954        # test with explicit base tuple
955        class C(object):
956            pass
957        error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
958                                                   (error3, C))
959        self.assertTrue(issubclass(error4, error3))
960        self.assertTrue(issubclass(error4, C))
961        self.assertEqual(error4.__doc__, doc4)
962
963        # test with explicit dictionary
964        error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
965                                                   error4, {'a': 1})
966        self.assertTrue(issubclass(error5, error4))
967        self.assertEqual(error5.a, 1)
968        self.assertEqual(error5.__doc__, "")
969
970    @cpython_only
971    def test_memory_error_cleanup(self):
972        # Issue #5437: preallocated MemoryError instances should not keep
973        # traceback objects alive.
974        from _testcapi import raise_memoryerror
975        class C:
976            pass
977        wr = None
978        def inner():
979            nonlocal wr
980            c = C()
981            wr = weakref.ref(c)
982            raise_memoryerror()
983        # We cannot use assertRaises since it manually deletes the traceback
984        try:
985            inner()
986        except MemoryError as e:
987            self.assertNotEqual(wr(), None)
988        else:
989            self.fail("MemoryError not raised")
990        self.assertEqual(wr(), None)
991
992    @no_tracing
993    def test_recursion_error_cleanup(self):
994        # Same test as above, but with "recursion exceeded" errors
995        class C:
996            pass
997        wr = None
998        def inner():
999            nonlocal wr
1000            c = C()
1001            wr = weakref.ref(c)
1002            inner()
1003        # We cannot use assertRaises since it manually deletes the traceback
1004        try:
1005            inner()
1006        except RecursionError as e:
1007            self.assertNotEqual(wr(), None)
1008        else:
1009            self.fail("RecursionError not raised")
1010        self.assertEqual(wr(), None)
1011
1012    def test_errno_ENOTDIR(self):
1013        # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
1014        with self.assertRaises(OSError) as cm:
1015            os.listdir(__file__)
1016        self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception)
1017
1018    def test_unraisable(self):
1019        # Issue #22836: PyErr_WriteUnraisable() should give sensible reports
1020        class BrokenDel:
1021            def __del__(self):
1022                exc = ValueError("del is broken")
1023                # The following line is included in the traceback report:
1024                raise exc
1025
1026        class BrokenRepr(BrokenDel):
1027            def __repr__(self):
1028                raise AttributeError("repr() is broken")
1029
1030        class BrokenExceptionDel:
1031            def __del__(self):
1032                exc = BrokenStrException()
1033                # The following line is included in the traceback report:
1034                raise exc
1035
1036        for test_class in (BrokenDel, BrokenRepr, BrokenExceptionDel):
1037            with self.subTest(test_class):
1038                obj = test_class()
1039                with captured_stderr() as stderr:
1040                    del obj
1041                report = stderr.getvalue()
1042                self.assertIn("Exception ignored", report)
1043                if test_class is BrokenRepr:
1044                    self.assertIn("<object repr() failed>", report)
1045                else:
1046                    self.assertIn(test_class.__del__.__qualname__, report)
1047                self.assertIn("test_exceptions.py", report)
1048                self.assertIn("raise exc", report)
1049                if test_class is BrokenExceptionDel:
1050                    self.assertIn("BrokenStrException", report)
1051                    self.assertIn("<exception str() failed>", report)
1052                else:
1053                    self.assertIn("ValueError", report)
1054                    self.assertIn("del is broken", report)
1055                self.assertTrue(report.endswith("\n"))
1056
1057    def test_unhandled(self):
1058        # Check for sensible reporting of unhandled exceptions
1059        for exc_type in (ValueError, BrokenStrException):
1060            with self.subTest(exc_type):
1061                try:
1062                    exc = exc_type("test message")
1063                    # The following line is included in the traceback report:
1064                    raise exc
1065                except exc_type:
1066                    with captured_stderr() as stderr:
1067                        sys.__excepthook__(*sys.exc_info())
1068                report = stderr.getvalue()
1069                self.assertIn("test_exceptions.py", report)
1070                self.assertIn("raise exc", report)
1071                self.assertIn(exc_type.__name__, report)
1072                if exc_type is BrokenStrException:
1073                    self.assertIn("<exception str() failed>", report)
1074                else:
1075                    self.assertIn("test message", report)
1076                self.assertTrue(report.endswith("\n"))
1077
1078
1079class ImportErrorTests(unittest.TestCase):
1080
1081    def test_attributes(self):
1082        # Setting 'name' and 'path' should not be a problem.
1083        exc = ImportError('test')
1084        self.assertIsNone(exc.name)
1085        self.assertIsNone(exc.path)
1086
1087        exc = ImportError('test', name='somemodule')
1088        self.assertEqual(exc.name, 'somemodule')
1089        self.assertIsNone(exc.path)
1090
1091        exc = ImportError('test', path='somepath')
1092        self.assertEqual(exc.path, 'somepath')
1093        self.assertIsNone(exc.name)
1094
1095        exc = ImportError('test', path='somepath', name='somename')
1096        self.assertEqual(exc.name, 'somename')
1097        self.assertEqual(exc.path, 'somepath')
1098
1099        msg = "'invalid' is an invalid keyword argument for this function"
1100        with self.assertRaisesRegex(TypeError, msg):
1101            ImportError('test', invalid='keyword')
1102
1103        with self.assertRaisesRegex(TypeError, msg):
1104            ImportError('test', name='name', invalid='keyword')
1105
1106        with self.assertRaisesRegex(TypeError, msg):
1107            ImportError('test', path='path', invalid='keyword')
1108
1109        with self.assertRaisesRegex(TypeError, msg):
1110            ImportError(invalid='keyword')
1111
1112        with self.assertRaisesRegex(TypeError, msg):
1113            ImportError('test', invalid='keyword', another=True)
1114
1115    def test_non_str_argument(self):
1116        # Issue #15778
1117        with check_warnings(('', BytesWarning), quiet=True):
1118            arg = b'abc'
1119            exc = ImportError(arg)
1120            self.assertEqual(str(arg), str(exc))
1121
1122
1123if __name__ == '__main__':
1124    unittest.main()
1125