• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Python test set -- part 5, built-in exceptions
2
3import copy
4import os
5import sys
6import unittest
7import pickle
8import weakref
9import errno
10
11from test.support import (TESTFN, captured_stderr, check_impl_detail,
12                          check_warnings, cpython_only, gc_collect,
13                          no_tracing, unlink, import_module, script_helper,
14                          SuppressCrashReport)
15from test import support
16
17
18class NaiveException(Exception):
19    def __init__(self, x):
20        self.x = x
21
22class SlottedNaiveException(Exception):
23    __slots__ = ('x',)
24    def __init__(self, x):
25        self.x = x
26
27class BrokenStrException(Exception):
28    def __str__(self):
29        raise Exception("str() is broken")
30
31# XXX This is not really enough, each *operation* should be tested!
32
33class ExceptionTests(unittest.TestCase):
34
35    def raise_catch(self, exc, excname):
36        try:
37            raise exc("spam")
38        except exc as err:
39            buf1 = str(err)
40        try:
41            raise exc("spam")
42        except exc as err:
43            buf2 = str(err)
44        self.assertEqual(buf1, buf2)
45        self.assertEqual(exc.__name__, excname)
46
47    def testRaising(self):
48        self.raise_catch(AttributeError, "AttributeError")
49        self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")
50
51        self.raise_catch(EOFError, "EOFError")
52        fp = open(TESTFN, 'w')
53        fp.close()
54        fp = open(TESTFN, 'r')
55        savestdin = sys.stdin
56        try:
57            try:
58                import marshal
59                marshal.loads(b'')
60            except EOFError:
61                pass
62        finally:
63            sys.stdin = savestdin
64            fp.close()
65            unlink(TESTFN)
66
67        self.raise_catch(OSError, "OSError")
68        self.assertRaises(OSError, open, 'this file does not exist', 'r')
69
70        self.raise_catch(ImportError, "ImportError")
71        self.assertRaises(ImportError, __import__, "undefined_module")
72
73        self.raise_catch(IndexError, "IndexError")
74        x = []
75        self.assertRaises(IndexError, x.__getitem__, 10)
76
77        self.raise_catch(KeyError, "KeyError")
78        x = {}
79        self.assertRaises(KeyError, x.__getitem__, 'key')
80
81        self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")
82
83        self.raise_catch(MemoryError, "MemoryError")
84
85        self.raise_catch(NameError, "NameError")
86        try: x = undefined_variable
87        except NameError: pass
88
89        self.raise_catch(OverflowError, "OverflowError")
90        x = 1
91        for dummy in range(128):
92            x += x  # this simply shouldn't blow up
93
94        self.raise_catch(RuntimeError, "RuntimeError")
95        self.raise_catch(RecursionError, "RecursionError")
96
97        self.raise_catch(SyntaxError, "SyntaxError")
98        try: exec('/\n')
99        except SyntaxError: pass
100
101        self.raise_catch(IndentationError, "IndentationError")
102
103        self.raise_catch(TabError, "TabError")
104        try: compile("try:\n\t1/0\n    \t1/0\nfinally:\n pass\n",
105                     '<string>', 'exec')
106        except TabError: pass
107        else: self.fail("TabError not raised")
108
109        self.raise_catch(SystemError, "SystemError")
110
111        self.raise_catch(SystemExit, "SystemExit")
112        self.assertRaises(SystemExit, sys.exit, 0)
113
114        self.raise_catch(TypeError, "TypeError")
115        try: [] + ()
116        except TypeError: pass
117
118        self.raise_catch(ValueError, "ValueError")
119        self.assertRaises(ValueError, chr, 17<<16)
120
121        self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
122        try: x = 1/0
123        except ZeroDivisionError: pass
124
125        self.raise_catch(Exception, "Exception")
126        try: x = 1/0
127        except Exception as e: pass
128
129        self.raise_catch(StopAsyncIteration, "StopAsyncIteration")
130
131    def testSyntaxErrorMessage(self):
132        # make sure the right exception message is raised for each of
133        # these code fragments
134
135        def ckmsg(src, msg):
136            try:
137                compile(src, '<fragment>', 'exec')
138            except SyntaxError as e:
139                if e.msg != msg:
140                    self.fail("expected %s, got %s" % (msg, e.msg))
141            else:
142                self.fail("failed to get expected SyntaxError")
143
144        s = '''if 1:
145        try:
146            continue
147        except:
148            pass'''
149
150        ckmsg(s, "'continue' not properly in loop")
151        ckmsg("continue\n", "'continue' not properly in loop")
152
153    def testSyntaxErrorMissingParens(self):
154        def ckmsg(src, msg, exception=SyntaxError):
155            try:
156                compile(src, '<fragment>', 'exec')
157            except exception as e:
158                if e.msg != msg:
159                    self.fail("expected %s, got %s" % (msg, e.msg))
160            else:
161                self.fail("failed to get expected SyntaxError")
162
163        s = '''print "old style"'''
164        ckmsg(s, "Missing parentheses in call to 'print'. "
165                 "Did you mean print(\"old style\")?")
166
167        s = '''print "old style",'''
168        ckmsg(s, "Missing parentheses in call to 'print'. "
169                 "Did you mean print(\"old style\", end=\" \")?")
170
171        s = '''exec "old style"'''
172        ckmsg(s, "Missing parentheses in call to 'exec'")
173
174        # should not apply to subclasses, see issue #31161
175        s = '''if True:\nprint "No indent"'''
176        ckmsg(s, "expected an indented block", IndentationError)
177
178        s = '''if True:\n        print()\n\texec "mixed tabs and spaces"'''
179        ckmsg(s, "inconsistent use of tabs and spaces in indentation", TabError)
180
181    def testSyntaxErrorOffset(self):
182        def check(src, lineno, offset, encoding='utf-8'):
183            with self.assertRaises(SyntaxError) as cm:
184                compile(src, '<fragment>', 'exec')
185            self.assertEqual(cm.exception.lineno, lineno)
186            self.assertEqual(cm.exception.offset, offset)
187            if cm.exception.text is not None:
188                if not isinstance(src, str):
189                    src = src.decode(encoding, 'replace')
190                line = src.split('\n')[lineno-1]
191                self.assertEqual(cm.exception.text.rstrip('\n'), line)
192
193        check('def fact(x):\n\treturn x!\n', 2, 10)
194        check('1 +\n', 1, 4)
195        check('def spam():\n  print(1)\n print(2)', 3, 10)
196        check('Python = "Python" +', 1, 20)
197        check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20)
198        check(b'# -*- coding: cp1251 -*-\nPython = "\xcf\xb3\xf2\xee\xed" +',
199              2, 19, encoding='cp1251')
200        check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 18)
201        check('x = "a', 1, 7)
202        check('lambda x: x = 2', 1, 1)
203
204        # Errors thrown by compile.c
205        check('class foo:return 1', 1, 11)
206        check('def f():\n  continue', 2, 3)
207        check('def f():\n  break', 2, 3)
208        check('try:\n  pass\nexcept:\n  pass\nexcept ValueError:\n  pass', 2, 3)
209
210        # Errors thrown by tokenizer.c
211        check('(0x+1)', 1, 3)
212        check('x = 0xI', 1, 6)
213        check('0010 + 2', 1, 4)
214        check('x = 32e-+4', 1, 8)
215        check('x = 0o9', 1, 6)
216        check('\u03b1 = 0xI', 1, 6)
217        check(b'\xce\xb1 = 0xI', 1, 6)
218        check(b'# -*- coding: iso8859-7 -*-\n\xe1 = 0xI', 2, 6,
219              encoding='iso8859-7')
220
221        # Errors thrown by symtable.c
222        check('x = [(yield i) for i in range(3)]', 1, 5)
223        check('def f():\n  from _ import *', 1, 1)
224        check('def f(x, x):\n  pass', 1, 1)
225        check('def f(x):\n  nonlocal x', 2, 3)
226        check('def f(x):\n  x = 1\n  global x', 3, 3)
227        check('nonlocal x', 1, 1)
228        check('def f():\n  global x\n  nonlocal x', 2, 3)
229
230        # Errors thrown by ast.c
231        check('for 1 in []: pass', 1, 5)
232        check('def f(*):\n  pass', 1, 7)
233        check('[*x for x in xs]', 1, 2)
234        check('def f():\n  x, y: int', 2, 3)
235        check('(yield i) = 2', 1, 1)
236        check('foo(x for x in range(10), 100)', 1, 5)
237        check('foo(1=2)', 1, 5)
238
239        # Errors thrown by future.c
240        check('from __future__ import doesnt_exist', 1, 1)
241        check('from __future__ import braces', 1, 1)
242        check('x=1\nfrom __future__ import division', 2, 1)
243
244
245    @cpython_only
246    def testSettingException(self):
247        # test that setting an exception at the C level works even if the
248        # exception object can't be constructed.
249
250        class BadException(Exception):
251            def __init__(self_):
252                raise RuntimeError("can't instantiate BadException")
253
254        class InvalidException:
255            pass
256
257        def test_capi1():
258            import _testcapi
259            try:
260                _testcapi.raise_exception(BadException, 1)
261            except TypeError as err:
262                exc, err, tb = sys.exc_info()
263                co = tb.tb_frame.f_code
264                self.assertEqual(co.co_name, "test_capi1")
265                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
266            else:
267                self.fail("Expected exception")
268
269        def test_capi2():
270            import _testcapi
271            try:
272                _testcapi.raise_exception(BadException, 0)
273            except RuntimeError as err:
274                exc, err, tb = sys.exc_info()
275                co = tb.tb_frame.f_code
276                self.assertEqual(co.co_name, "__init__")
277                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
278                co2 = tb.tb_frame.f_back.f_code
279                self.assertEqual(co2.co_name, "test_capi2")
280            else:
281                self.fail("Expected exception")
282
283        def test_capi3():
284            import _testcapi
285            self.assertRaises(SystemError, _testcapi.raise_exception,
286                              InvalidException, 1)
287
288        if not sys.platform.startswith('java'):
289            test_capi1()
290            test_capi2()
291            test_capi3()
292
293    def test_WindowsError(self):
294        try:
295            WindowsError
296        except NameError:
297            pass
298        else:
299            self.assertIs(WindowsError, OSError)
300            self.assertEqual(str(OSError(1001)), "1001")
301            self.assertEqual(str(OSError(1001, "message")),
302                             "[Errno 1001] message")
303            # POSIX errno (9 aka EBADF) is untranslated
304            w = OSError(9, 'foo', 'bar')
305            self.assertEqual(w.errno, 9)
306            self.assertEqual(w.winerror, None)
307            self.assertEqual(str(w), "[Errno 9] foo: 'bar'")
308            # ERROR_PATH_NOT_FOUND (win error 3) becomes ENOENT (2)
309            w = OSError(0, 'foo', 'bar', 3)
310            self.assertEqual(w.errno, 2)
311            self.assertEqual(w.winerror, 3)
312            self.assertEqual(w.strerror, 'foo')
313            self.assertEqual(w.filename, 'bar')
314            self.assertEqual(w.filename2, None)
315            self.assertEqual(str(w), "[WinError 3] foo: 'bar'")
316            # Unknown win error becomes EINVAL (22)
317            w = OSError(0, 'foo', None, 1001)
318            self.assertEqual(w.errno, 22)
319            self.assertEqual(w.winerror, 1001)
320            self.assertEqual(w.strerror, 'foo')
321            self.assertEqual(w.filename, None)
322            self.assertEqual(w.filename2, None)
323            self.assertEqual(str(w), "[WinError 1001] foo")
324            # Non-numeric "errno"
325            w = OSError('bar', 'foo')
326            self.assertEqual(w.errno, 'bar')
327            self.assertEqual(w.winerror, None)
328            self.assertEqual(w.strerror, 'foo')
329            self.assertEqual(w.filename, None)
330            self.assertEqual(w.filename2, None)
331
332    @unittest.skipUnless(sys.platform == 'win32',
333                         'test specific to Windows')
334    def test_windows_message(self):
335        """Should fill in unknown error code in Windows error message"""
336        ctypes = import_module('ctypes')
337        # this error code has no message, Python formats it as hexadecimal
338        code = 3765269347
339        with self.assertRaisesRegex(OSError, 'Windows Error 0x%x' % code):
340            ctypes.pythonapi.PyErr_SetFromWindowsErr(code)
341
342    def testAttributes(self):
343        # test that exception attributes are happy
344
345        exceptionList = [
346            (BaseException, (), {'args' : ()}),
347            (BaseException, (1, ), {'args' : (1,)}),
348            (BaseException, ('foo',),
349                {'args' : ('foo',)}),
350            (BaseException, ('foo', 1),
351                {'args' : ('foo', 1)}),
352            (SystemExit, ('foo',),
353                {'args' : ('foo',), 'code' : 'foo'}),
354            (OSError, ('foo',),
355                {'args' : ('foo',), 'filename' : None, 'filename2' : None,
356                 'errno' : None, 'strerror' : None}),
357            (OSError, ('foo', 'bar'),
358                {'args' : ('foo', 'bar'),
359                 'filename' : None, 'filename2' : None,
360                 'errno' : 'foo', 'strerror' : 'bar'}),
361            (OSError, ('foo', 'bar', 'baz'),
362                {'args' : ('foo', 'bar'),
363                 'filename' : 'baz', 'filename2' : None,
364                 'errno' : 'foo', 'strerror' : 'bar'}),
365            (OSError, ('foo', 'bar', 'baz', None, 'quux'),
366                {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}),
367            (OSError, ('errnoStr', 'strErrorStr', 'filenameStr'),
368                {'args' : ('errnoStr', 'strErrorStr'),
369                 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
370                 'filename' : 'filenameStr'}),
371            (OSError, (1, 'strErrorStr', 'filenameStr'),
372                {'args' : (1, 'strErrorStr'), 'errno' : 1,
373                 'strerror' : 'strErrorStr',
374                 'filename' : 'filenameStr', 'filename2' : None}),
375            (SyntaxError, (), {'msg' : None, 'text' : None,
376                'filename' : None, 'lineno' : None, 'offset' : None,
377                'print_file_and_line' : None}),
378            (SyntaxError, ('msgStr',),
379                {'args' : ('msgStr',), 'text' : None,
380                 'print_file_and_line' : None, 'msg' : 'msgStr',
381                 'filename' : None, 'lineno' : None, 'offset' : None}),
382            (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
383                           'textStr')),
384                {'offset' : 'offsetStr', 'text' : 'textStr',
385                 'args' : ('msgStr', ('filenameStr', 'linenoStr',
386                                      'offsetStr', 'textStr')),
387                 'print_file_and_line' : None, 'msg' : 'msgStr',
388                 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
389            (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
390                           'textStr', 'print_file_and_lineStr'),
391                {'text' : None,
392                 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
393                           'textStr', 'print_file_and_lineStr'),
394                 'print_file_and_line' : None, 'msg' : 'msgStr',
395                 'filename' : None, 'lineno' : None, 'offset' : None}),
396            (UnicodeError, (), {'args' : (),}),
397            (UnicodeEncodeError, ('ascii', 'a', 0, 1,
398                                  'ordinal not in range'),
399                {'args' : ('ascii', 'a', 0, 1,
400                                           'ordinal not in range'),
401                 'encoding' : 'ascii', 'object' : 'a',
402                 'start' : 0, 'reason' : 'ordinal not in range'}),
403            (UnicodeDecodeError, ('ascii', bytearray(b'\xff'), 0, 1,
404                                  'ordinal not in range'),
405                {'args' : ('ascii', bytearray(b'\xff'), 0, 1,
406                                           'ordinal not in range'),
407                 'encoding' : 'ascii', 'object' : b'\xff',
408                 'start' : 0, 'reason' : 'ordinal not in range'}),
409            (UnicodeDecodeError, ('ascii', b'\xff', 0, 1,
410                                  'ordinal not in range'),
411                {'args' : ('ascii', b'\xff', 0, 1,
412                                           'ordinal not in range'),
413                 'encoding' : 'ascii', 'object' : b'\xff',
414                 'start' : 0, 'reason' : 'ordinal not in range'}),
415            (UnicodeTranslateError, ("\u3042", 0, 1, "ouch"),
416                {'args' : ('\u3042', 0, 1, 'ouch'),
417                 'object' : '\u3042', 'reason' : 'ouch',
418                 'start' : 0, 'end' : 1}),
419            (NaiveException, ('foo',),
420                {'args': ('foo',), 'x': 'foo'}),
421            (SlottedNaiveException, ('foo',),
422                {'args': ('foo',), 'x': 'foo'}),
423        ]
424        try:
425            # More tests are in test_WindowsError
426            exceptionList.append(
427                (WindowsError, (1, 'strErrorStr', 'filenameStr'),
428                    {'args' : (1, 'strErrorStr'),
429                     'strerror' : 'strErrorStr', 'winerror' : None,
430                     'errno' : 1,
431                     'filename' : 'filenameStr', 'filename2' : None})
432            )
433        except NameError:
434            pass
435
436        for exc, args, expected in exceptionList:
437            try:
438                e = exc(*args)
439            except:
440                print("\nexc=%r, args=%r" % (exc, args), file=sys.stderr)
441                raise
442            else:
443                # Verify module name
444                if not type(e).__name__.endswith('NaiveException'):
445                    self.assertEqual(type(e).__module__, 'builtins')
446                # Verify no ref leaks in Exc_str()
447                s = str(e)
448                for checkArgName in expected:
449                    value = getattr(e, checkArgName)
450                    self.assertEqual(repr(value),
451                                     repr(expected[checkArgName]),
452                                     '%r.%s == %r, expected %r' % (
453                                     e, checkArgName,
454                                     value, expected[checkArgName]))
455
456                # test for pickling support
457                for p in [pickle]:
458                    for protocol in range(p.HIGHEST_PROTOCOL + 1):
459                        s = p.dumps(e, protocol)
460                        new = p.loads(s)
461                        for checkArgName in expected:
462                            got = repr(getattr(new, checkArgName))
463                            want = repr(expected[checkArgName])
464                            self.assertEqual(got, want,
465                                             'pickled "%r", attribute "%s' %
466                                             (e, checkArgName))
467
468    def testWithTraceback(self):
469        try:
470            raise IndexError(4)
471        except:
472            tb = sys.exc_info()[2]
473
474        e = BaseException().with_traceback(tb)
475        self.assertIsInstance(e, BaseException)
476        self.assertEqual(e.__traceback__, tb)
477
478        e = IndexError(5).with_traceback(tb)
479        self.assertIsInstance(e, IndexError)
480        self.assertEqual(e.__traceback__, tb)
481
482        class MyException(Exception):
483            pass
484
485        e = MyException().with_traceback(tb)
486        self.assertIsInstance(e, MyException)
487        self.assertEqual(e.__traceback__, tb)
488
489    def testInvalidTraceback(self):
490        try:
491            Exception().__traceback__ = 5
492        except TypeError as e:
493            self.assertIn("__traceback__ must be a traceback", str(e))
494        else:
495            self.fail("No exception raised")
496
497    def testInvalidAttrs(self):
498        self.assertRaises(TypeError, setattr, Exception(), '__cause__', 1)
499        self.assertRaises(TypeError, delattr, Exception(), '__cause__')
500        self.assertRaises(TypeError, setattr, Exception(), '__context__', 1)
501        self.assertRaises(TypeError, delattr, Exception(), '__context__')
502
503    def testNoneClearsTracebackAttr(self):
504        try:
505            raise IndexError(4)
506        except:
507            tb = sys.exc_info()[2]
508
509        e = Exception()
510        e.__traceback__ = tb
511        e.__traceback__ = None
512        self.assertEqual(e.__traceback__, None)
513
514    def testChainingAttrs(self):
515        e = Exception()
516        self.assertIsNone(e.__context__)
517        self.assertIsNone(e.__cause__)
518
519        e = TypeError()
520        self.assertIsNone(e.__context__)
521        self.assertIsNone(e.__cause__)
522
523        class MyException(OSError):
524            pass
525
526        e = MyException()
527        self.assertIsNone(e.__context__)
528        self.assertIsNone(e.__cause__)
529
530    def testChainingDescriptors(self):
531        try:
532            raise Exception()
533        except Exception as exc:
534            e = exc
535
536        self.assertIsNone(e.__context__)
537        self.assertIsNone(e.__cause__)
538        self.assertFalse(e.__suppress_context__)
539
540        e.__context__ = NameError()
541        e.__cause__ = None
542        self.assertIsInstance(e.__context__, NameError)
543        self.assertIsNone(e.__cause__)
544        self.assertTrue(e.__suppress_context__)
545        e.__suppress_context__ = False
546        self.assertFalse(e.__suppress_context__)
547
548    def testKeywordArgs(self):
549        # test that builtin exception don't take keyword args,
550        # but user-defined subclasses can if they want
551        self.assertRaises(TypeError, BaseException, a=1)
552
553        class DerivedException(BaseException):
554            def __init__(self, fancy_arg):
555                BaseException.__init__(self)
556                self.fancy_arg = fancy_arg
557
558        x = DerivedException(fancy_arg=42)
559        self.assertEqual(x.fancy_arg, 42)
560
561    @no_tracing
562    def testInfiniteRecursion(self):
563        def f():
564            return f()
565        self.assertRaises(RecursionError, f)
566
567        def g():
568            try:
569                return g()
570            except ValueError:
571                return -1
572        self.assertRaises(RecursionError, g)
573
574    def test_str(self):
575        # Make sure both instances and classes have a str representation.
576        self.assertTrue(str(Exception))
577        self.assertTrue(str(Exception('a')))
578        self.assertTrue(str(Exception('a', 'b')))
579
580    def testExceptionCleanupNames(self):
581        # Make sure the local variable bound to the exception instance by
582        # an "except" statement is only visible inside the except block.
583        try:
584            raise Exception()
585        except Exception as e:
586            self.assertTrue(e)
587            del e
588        self.assertNotIn('e', locals())
589
590    def testExceptionCleanupState(self):
591        # Make sure exception state is cleaned up as soon as the except
592        # block is left. See #2507
593
594        class MyException(Exception):
595            def __init__(self, obj):
596                self.obj = obj
597        class MyObj:
598            pass
599
600        def inner_raising_func():
601            # Create some references in exception value and traceback
602            local_ref = obj
603            raise MyException(obj)
604
605        # Qualified "except" with "as"
606        obj = MyObj()
607        wr = weakref.ref(obj)
608        try:
609            inner_raising_func()
610        except MyException as e:
611            pass
612        obj = None
613        obj = wr()
614        self.assertIsNone(obj)
615
616        # Qualified "except" without "as"
617        obj = MyObj()
618        wr = weakref.ref(obj)
619        try:
620            inner_raising_func()
621        except MyException:
622            pass
623        obj = None
624        obj = wr()
625        self.assertIsNone(obj)
626
627        # Bare "except"
628        obj = MyObj()
629        wr = weakref.ref(obj)
630        try:
631            inner_raising_func()
632        except:
633            pass
634        obj = None
635        obj = wr()
636        self.assertIsNone(obj)
637
638        # "except" with premature block leave
639        obj = MyObj()
640        wr = weakref.ref(obj)
641        for i in [0]:
642            try:
643                inner_raising_func()
644            except:
645                break
646        obj = None
647        obj = wr()
648        self.assertIsNone(obj)
649
650        # "except" block raising another exception
651        obj = MyObj()
652        wr = weakref.ref(obj)
653        try:
654            try:
655                inner_raising_func()
656            except:
657                raise KeyError
658        except KeyError as e:
659            # We want to test that the except block above got rid of
660            # the exception raised in inner_raising_func(), but it
661            # also ends up in the __context__ of the KeyError, so we
662            # must clear the latter manually for our test to succeed.
663            e.__context__ = None
664            obj = None
665            obj = wr()
666            # guarantee no ref cycles on CPython (don't gc_collect)
667            if check_impl_detail(cpython=False):
668                gc_collect()
669            self.assertIsNone(obj)
670
671        # Some complicated construct
672        obj = MyObj()
673        wr = weakref.ref(obj)
674        try:
675            inner_raising_func()
676        except MyException:
677            try:
678                try:
679                    raise
680                finally:
681                    raise
682            except MyException:
683                pass
684        obj = None
685        if check_impl_detail(cpython=False):
686            gc_collect()
687        obj = wr()
688        self.assertIsNone(obj)
689
690        # Inside an exception-silencing "with" block
691        class Context:
692            def __enter__(self):
693                return self
694            def __exit__ (self, exc_type, exc_value, exc_tb):
695                return True
696        obj = MyObj()
697        wr = weakref.ref(obj)
698        with Context():
699            inner_raising_func()
700        obj = None
701        if check_impl_detail(cpython=False):
702            gc_collect()
703        obj = wr()
704        self.assertIsNone(obj)
705
706    def test_exception_target_in_nested_scope(self):
707        # issue 4617: This used to raise a SyntaxError
708        # "can not delete variable 'e' referenced in nested scope"
709        def print_error():
710            e
711        try:
712            something
713        except Exception as e:
714            print_error()
715            # implicit "del e" here
716
717    def test_generator_leaking(self):
718        # Test that generator exception state doesn't leak into the calling
719        # frame
720        def yield_raise():
721            try:
722                raise KeyError("caught")
723            except KeyError:
724                yield sys.exc_info()[0]
725                yield sys.exc_info()[0]
726            yield sys.exc_info()[0]
727        g = yield_raise()
728        self.assertEqual(next(g), KeyError)
729        self.assertEqual(sys.exc_info()[0], None)
730        self.assertEqual(next(g), KeyError)
731        self.assertEqual(sys.exc_info()[0], None)
732        self.assertEqual(next(g), None)
733
734        # Same test, but inside an exception handler
735        try:
736            raise TypeError("foo")
737        except TypeError:
738            g = yield_raise()
739            self.assertEqual(next(g), KeyError)
740            self.assertEqual(sys.exc_info()[0], TypeError)
741            self.assertEqual(next(g), KeyError)
742            self.assertEqual(sys.exc_info()[0], TypeError)
743            self.assertEqual(next(g), TypeError)
744            del g
745            self.assertEqual(sys.exc_info()[0], TypeError)
746
747    def test_generator_leaking2(self):
748        # See issue 12475.
749        def g():
750            yield
751        try:
752            raise RuntimeError
753        except RuntimeError:
754            it = g()
755            next(it)
756        try:
757            next(it)
758        except StopIteration:
759            pass
760        self.assertEqual(sys.exc_info(), (None, None, None))
761
762    def test_generator_leaking3(self):
763        # See issue #23353.  When gen.throw() is called, the caller's
764        # exception state should be save and restored.
765        def g():
766            try:
767                yield
768            except ZeroDivisionError:
769                yield sys.exc_info()[1]
770        it = g()
771        next(it)
772        try:
773            1/0
774        except ZeroDivisionError as e:
775            self.assertIs(sys.exc_info()[1], e)
776            gen_exc = it.throw(e)
777            self.assertIs(sys.exc_info()[1], e)
778            self.assertIs(gen_exc, e)
779        self.assertEqual(sys.exc_info(), (None, None, None))
780
781    def test_generator_leaking4(self):
782        # See issue #23353.  When an exception is raised by a generator,
783        # the caller's exception state should still be restored.
784        def g():
785            try:
786                1/0
787            except ZeroDivisionError:
788                yield sys.exc_info()[0]
789                raise
790        it = g()
791        try:
792            raise TypeError
793        except TypeError:
794            # The caller's exception state (TypeError) is temporarily
795            # saved in the generator.
796            tp = next(it)
797        self.assertIs(tp, ZeroDivisionError)
798        try:
799            next(it)
800            # We can't check it immediately, but while next() returns
801            # with an exception, it shouldn't have restored the old
802            # exception state (TypeError).
803        except ZeroDivisionError as e:
804            self.assertIs(sys.exc_info()[1], e)
805        # We used to find TypeError here.
806        self.assertEqual(sys.exc_info(), (None, None, None))
807
808    def test_generator_doesnt_retain_old_exc(self):
809        def g():
810            self.assertIsInstance(sys.exc_info()[1], RuntimeError)
811            yield
812            self.assertEqual(sys.exc_info(), (None, None, None))
813        it = g()
814        try:
815            raise RuntimeError
816        except RuntimeError:
817            next(it)
818        self.assertRaises(StopIteration, next, it)
819
820    def test_generator_finalizing_and_exc_info(self):
821        # See #7173
822        def simple_gen():
823            yield 1
824        def run_gen():
825            gen = simple_gen()
826            try:
827                raise RuntimeError
828            except RuntimeError:
829                return next(gen)
830        run_gen()
831        gc_collect()
832        self.assertEqual(sys.exc_info(), (None, None, None))
833
834    def _check_generator_cleanup_exc_state(self, testfunc):
835        # Issue #12791: exception state is cleaned up as soon as a generator
836        # is closed (reference cycles are broken).
837        class MyException(Exception):
838            def __init__(self, obj):
839                self.obj = obj
840        class MyObj:
841            pass
842
843        def raising_gen():
844            try:
845                raise MyException(obj)
846            except MyException:
847                yield
848
849        obj = MyObj()
850        wr = weakref.ref(obj)
851        g = raising_gen()
852        next(g)
853        testfunc(g)
854        g = obj = None
855        obj = wr()
856        self.assertIsNone(obj)
857
858    def test_generator_throw_cleanup_exc_state(self):
859        def do_throw(g):
860            try:
861                g.throw(RuntimeError())
862            except RuntimeError:
863                pass
864        self._check_generator_cleanup_exc_state(do_throw)
865
866    def test_generator_close_cleanup_exc_state(self):
867        def do_close(g):
868            g.close()
869        self._check_generator_cleanup_exc_state(do_close)
870
871    def test_generator_del_cleanup_exc_state(self):
872        def do_del(g):
873            g = None
874        self._check_generator_cleanup_exc_state(do_del)
875
876    def test_generator_next_cleanup_exc_state(self):
877        def do_next(g):
878            try:
879                next(g)
880            except StopIteration:
881                pass
882            else:
883                self.fail("should have raised StopIteration")
884        self._check_generator_cleanup_exc_state(do_next)
885
886    def test_generator_send_cleanup_exc_state(self):
887        def do_send(g):
888            try:
889                g.send(None)
890            except StopIteration:
891                pass
892            else:
893                self.fail("should have raised StopIteration")
894        self._check_generator_cleanup_exc_state(do_send)
895
896    def test_3114(self):
897        # Bug #3114: in its destructor, MyObject retrieves a pointer to
898        # obsolete and/or deallocated objects.
899        class MyObject:
900            def __del__(self):
901                nonlocal e
902                e = sys.exc_info()
903        e = ()
904        try:
905            raise Exception(MyObject())
906        except:
907            pass
908        self.assertEqual(e, (None, None, None))
909
910    def test_unicode_change_attributes(self):
911        # See issue 7309. This was a crasher.
912
913        u = UnicodeEncodeError('baz', 'xxxxx', 1, 5, 'foo')
914        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: foo")
915        u.end = 2
916        self.assertEqual(str(u), "'baz' codec can't encode character '\\x78' in position 1: foo")
917        u.end = 5
918        u.reason = 0x345345345345345345
919        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: 965230951443685724997")
920        u.encoding = 4000
921        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1-4: 965230951443685724997")
922        u.start = 1000
923        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1000-4: 965230951443685724997")
924
925        u = UnicodeDecodeError('baz', b'xxxxx', 1, 5, 'foo')
926        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: foo")
927        u.end = 2
928        self.assertEqual(str(u), "'baz' codec can't decode byte 0x78 in position 1: foo")
929        u.end = 5
930        u.reason = 0x345345345345345345
931        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: 965230951443685724997")
932        u.encoding = 4000
933        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1-4: 965230951443685724997")
934        u.start = 1000
935        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1000-4: 965230951443685724997")
936
937        u = UnicodeTranslateError('xxxx', 1, 5, 'foo')
938        self.assertEqual(str(u), "can't translate characters in position 1-4: foo")
939        u.end = 2
940        self.assertEqual(str(u), "can't translate character '\\x78' in position 1: foo")
941        u.end = 5
942        u.reason = 0x345345345345345345
943        self.assertEqual(str(u), "can't translate characters in position 1-4: 965230951443685724997")
944        u.start = 1000
945        self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997")
946
947    def test_unicode_errors_no_object(self):
948        # See issue #21134.
949        klasses = UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError
950        for klass in klasses:
951            self.assertEqual(str(klass.__new__(klass)), "")
952
953    @no_tracing
954    def test_badisinstance(self):
955        # Bug #2542: if issubclass(e, MyException) raises an exception,
956        # it should be ignored
957        class Meta(type):
958            def __subclasscheck__(cls, subclass):
959                raise ValueError()
960        class MyException(Exception, metaclass=Meta):
961            pass
962
963        with captured_stderr() as stderr:
964            try:
965                raise KeyError()
966            except MyException as e:
967                self.fail("exception should not be a MyException")
968            except KeyError:
969                pass
970            except:
971                self.fail("Should have raised KeyError")
972            else:
973                self.fail("Should have raised KeyError")
974
975        def g():
976            try:
977                return g()
978            except RecursionError:
979                return sys.exc_info()
980        e, v, tb = g()
981        self.assertIsInstance(v, RecursionError, type(v))
982        self.assertIn("maximum recursion depth exceeded", str(v))
983
984    @cpython_only
985    def test_recursion_normalizing_exception(self):
986        # Issue #22898.
987        # Test that a RecursionError is raised when tstate->recursion_depth is
988        # equal to recursion_limit in PyErr_NormalizeException() and check
989        # that a ResourceWarning is printed.
990        # Prior to #22898, the recursivity of PyErr_NormalizeException() was
991        # controlled by tstate->recursion_depth and a PyExc_RecursionErrorInst
992        # singleton was being used in that case, that held traceback data and
993        # locals indefinitely and would cause a segfault in _PyExc_Fini() upon
994        # finalization of these locals.
995        code = """if 1:
996            import sys
997            from _testcapi import get_recursion_depth
998
999            class MyException(Exception): pass
1000
1001            def setrecursionlimit(depth):
1002                while 1:
1003                    try:
1004                        sys.setrecursionlimit(depth)
1005                        return depth
1006                    except RecursionError:
1007                        # sys.setrecursionlimit() raises a RecursionError if
1008                        # the new recursion limit is too low (issue #25274).
1009                        depth += 1
1010
1011            def recurse(cnt):
1012                cnt -= 1
1013                if cnt:
1014                    recurse(cnt)
1015                else:
1016                    generator.throw(MyException)
1017
1018            def gen():
1019                f = open(%a, mode='rb', buffering=0)
1020                yield
1021
1022            generator = gen()
1023            next(generator)
1024            recursionlimit = sys.getrecursionlimit()
1025            depth = get_recursion_depth()
1026            try:
1027                # Upon the last recursive invocation of recurse(),
1028                # tstate->recursion_depth is equal to (recursion_limit - 1)
1029                # and is equal to recursion_limit when _gen_throw() calls
1030                # PyErr_NormalizeException().
1031                recurse(setrecursionlimit(depth + 2) - depth - 1)
1032            finally:
1033                sys.setrecursionlimit(recursionlimit)
1034                print('Done.')
1035        """ % __file__
1036        rc, out, err = script_helper.assert_python_failure("-Wd", "-c", code)
1037        # Check that the program does not fail with SIGABRT.
1038        self.assertEqual(rc, 1)
1039        self.assertIn(b'RecursionError', err)
1040        self.assertIn(b'ResourceWarning', err)
1041        self.assertIn(b'Done.', out)
1042
1043    @cpython_only
1044    def test_recursion_normalizing_infinite_exception(self):
1045        # Issue #30697. Test that a RecursionError is raised when
1046        # PyErr_NormalizeException() maximum recursion depth has been
1047        # exceeded.
1048        code = """if 1:
1049            import _testcapi
1050            try:
1051                raise _testcapi.RecursingInfinitelyError
1052            finally:
1053                print('Done.')
1054        """
1055        rc, out, err = script_helper.assert_python_failure("-c", code)
1056        self.assertEqual(rc, 1)
1057        self.assertIn(b'RecursionError: maximum recursion depth exceeded '
1058                      b'while normalizing an exception', err)
1059        self.assertIn(b'Done.', out)
1060
1061    @cpython_only
1062    def test_recursion_normalizing_with_no_memory(self):
1063        # Issue #30697. Test that in the abort that occurs when there is no
1064        # memory left and the size of the Python frames stack is greater than
1065        # the size of the list of preallocated MemoryError instances, the
1066        # Fatal Python error message mentions MemoryError.
1067        code = """if 1:
1068            import _testcapi
1069            class C(): pass
1070            def recurse(cnt):
1071                cnt -= 1
1072                if cnt:
1073                    recurse(cnt)
1074                else:
1075                    _testcapi.set_nomemory(0)
1076                    C()
1077            recurse(16)
1078        """
1079        with SuppressCrashReport():
1080            rc, out, err = script_helper.assert_python_failure("-c", code)
1081            self.assertIn(b'Fatal Python error: Cannot recover from '
1082                          b'MemoryErrors while normalizing exceptions.', err)
1083
1084    @cpython_only
1085    def test_MemoryError(self):
1086        # PyErr_NoMemory always raises the same exception instance.
1087        # Check that the traceback is not doubled.
1088        import traceback
1089        from _testcapi import raise_memoryerror
1090        def raiseMemError():
1091            try:
1092                raise_memoryerror()
1093            except MemoryError as e:
1094                tb = e.__traceback__
1095            else:
1096                self.fail("Should have raises a MemoryError")
1097            return traceback.format_tb(tb)
1098
1099        tb1 = raiseMemError()
1100        tb2 = raiseMemError()
1101        self.assertEqual(tb1, tb2)
1102
1103    @cpython_only
1104    def test_exception_with_doc(self):
1105        import _testcapi
1106        doc2 = "This is a test docstring."
1107        doc4 = "This is another test docstring."
1108
1109        self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
1110                          "error1")
1111
1112        # test basic usage of PyErr_NewException
1113        error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
1114        self.assertIs(type(error1), type)
1115        self.assertTrue(issubclass(error1, Exception))
1116        self.assertIsNone(error1.__doc__)
1117
1118        # test with given docstring
1119        error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
1120        self.assertEqual(error2.__doc__, doc2)
1121
1122        # test with explicit base (without docstring)
1123        error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
1124                                                   base=error2)
1125        self.assertTrue(issubclass(error3, error2))
1126
1127        # test with explicit base tuple
1128        class C(object):
1129            pass
1130        error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
1131                                                   (error3, C))
1132        self.assertTrue(issubclass(error4, error3))
1133        self.assertTrue(issubclass(error4, C))
1134        self.assertEqual(error4.__doc__, doc4)
1135
1136        # test with explicit dictionary
1137        error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
1138                                                   error4, {'a': 1})
1139        self.assertTrue(issubclass(error5, error4))
1140        self.assertEqual(error5.a, 1)
1141        self.assertEqual(error5.__doc__, "")
1142
1143    @cpython_only
1144    def test_memory_error_cleanup(self):
1145        # Issue #5437: preallocated MemoryError instances should not keep
1146        # traceback objects alive.
1147        from _testcapi import raise_memoryerror
1148        class C:
1149            pass
1150        wr = None
1151        def inner():
1152            nonlocal wr
1153            c = C()
1154            wr = weakref.ref(c)
1155            raise_memoryerror()
1156        # We cannot use assertRaises since it manually deletes the traceback
1157        try:
1158            inner()
1159        except MemoryError as e:
1160            self.assertNotEqual(wr(), None)
1161        else:
1162            self.fail("MemoryError not raised")
1163        self.assertEqual(wr(), None)
1164
1165    @no_tracing
1166    def test_recursion_error_cleanup(self):
1167        # Same test as above, but with "recursion exceeded" errors
1168        class C:
1169            pass
1170        wr = None
1171        def inner():
1172            nonlocal wr
1173            c = C()
1174            wr = weakref.ref(c)
1175            inner()
1176        # We cannot use assertRaises since it manually deletes the traceback
1177        try:
1178            inner()
1179        except RecursionError as e:
1180            self.assertNotEqual(wr(), None)
1181        else:
1182            self.fail("RecursionError not raised")
1183        self.assertEqual(wr(), None)
1184
1185    def test_errno_ENOTDIR(self):
1186        # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
1187        with self.assertRaises(OSError) as cm:
1188            os.listdir(__file__)
1189        self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception)
1190
1191    def test_unraisable(self):
1192        # Issue #22836: PyErr_WriteUnraisable() should give sensible reports
1193        class BrokenDel:
1194            def __del__(self):
1195                exc = ValueError("del is broken")
1196                # The following line is included in the traceback report:
1197                raise exc
1198
1199        obj = BrokenDel()
1200        with support.catch_unraisable_exception() as cm:
1201            del obj
1202
1203            self.assertEqual(cm.unraisable.object, BrokenDel.__del__)
1204            self.assertIsNotNone(cm.unraisable.exc_traceback)
1205
1206    def test_unhandled(self):
1207        # Check for sensible reporting of unhandled exceptions
1208        for exc_type in (ValueError, BrokenStrException):
1209            with self.subTest(exc_type):
1210                try:
1211                    exc = exc_type("test message")
1212                    # The following line is included in the traceback report:
1213                    raise exc
1214                except exc_type:
1215                    with captured_stderr() as stderr:
1216                        sys.__excepthook__(*sys.exc_info())
1217                report = stderr.getvalue()
1218                self.assertIn("test_exceptions.py", report)
1219                self.assertIn("raise exc", report)
1220                self.assertIn(exc_type.__name__, report)
1221                if exc_type is BrokenStrException:
1222                    self.assertIn("<exception str() failed>", report)
1223                else:
1224                    self.assertIn("test message", report)
1225                self.assertTrue(report.endswith("\n"))
1226
1227    @cpython_only
1228    def test_memory_error_in_PyErr_PrintEx(self):
1229        code = """if 1:
1230            import _testcapi
1231            class C(): pass
1232            _testcapi.set_nomemory(0, %d)
1233            C()
1234        """
1235
1236        # Issue #30817: Abort in PyErr_PrintEx() when no memory.
1237        # Span a large range of tests as the CPython code always evolves with
1238        # changes that add or remove memory allocations.
1239        for i in range(1, 20):
1240            rc, out, err = script_helper.assert_python_failure("-c", code % i)
1241            self.assertIn(rc, (1, 120))
1242            self.assertIn(b'MemoryError', err)
1243
1244    def test_yield_in_nested_try_excepts(self):
1245        #Issue #25612
1246        class MainError(Exception):
1247            pass
1248
1249        class SubError(Exception):
1250            pass
1251
1252        def main():
1253            try:
1254                raise MainError()
1255            except MainError:
1256                try:
1257                    yield
1258                except SubError:
1259                    pass
1260                raise
1261
1262        coro = main()
1263        coro.send(None)
1264        with self.assertRaises(MainError):
1265            coro.throw(SubError())
1266
1267    def test_generator_doesnt_retain_old_exc2(self):
1268        #Issue 28884#msg282532
1269        def g():
1270            try:
1271                raise ValueError
1272            except ValueError:
1273                yield 1
1274            self.assertEqual(sys.exc_info(), (None, None, None))
1275            yield 2
1276
1277        gen = g()
1278
1279        try:
1280            raise IndexError
1281        except IndexError:
1282            self.assertEqual(next(gen), 1)
1283        self.assertEqual(next(gen), 2)
1284
1285    def test_raise_in_generator(self):
1286        #Issue 25612#msg304117
1287        def g():
1288            yield 1
1289            raise
1290            yield 2
1291
1292        with self.assertRaises(ZeroDivisionError):
1293            i = g()
1294            try:
1295                1/0
1296            except:
1297                next(i)
1298                next(i)
1299
1300
1301class ImportErrorTests(unittest.TestCase):
1302
1303    def test_attributes(self):
1304        # Setting 'name' and 'path' should not be a problem.
1305        exc = ImportError('test')
1306        self.assertIsNone(exc.name)
1307        self.assertIsNone(exc.path)
1308
1309        exc = ImportError('test', name='somemodule')
1310        self.assertEqual(exc.name, 'somemodule')
1311        self.assertIsNone(exc.path)
1312
1313        exc = ImportError('test', path='somepath')
1314        self.assertEqual(exc.path, 'somepath')
1315        self.assertIsNone(exc.name)
1316
1317        exc = ImportError('test', path='somepath', name='somename')
1318        self.assertEqual(exc.name, 'somename')
1319        self.assertEqual(exc.path, 'somepath')
1320
1321        msg = "'invalid' is an invalid keyword argument for ImportError"
1322        with self.assertRaisesRegex(TypeError, msg):
1323            ImportError('test', invalid='keyword')
1324
1325        with self.assertRaisesRegex(TypeError, msg):
1326            ImportError('test', name='name', invalid='keyword')
1327
1328        with self.assertRaisesRegex(TypeError, msg):
1329            ImportError('test', path='path', invalid='keyword')
1330
1331        with self.assertRaisesRegex(TypeError, msg):
1332            ImportError(invalid='keyword')
1333
1334        with self.assertRaisesRegex(TypeError, msg):
1335            ImportError('test', invalid='keyword', another=True)
1336
1337    def test_reset_attributes(self):
1338        exc = ImportError('test', name='name', path='path')
1339        self.assertEqual(exc.args, ('test',))
1340        self.assertEqual(exc.msg, 'test')
1341        self.assertEqual(exc.name, 'name')
1342        self.assertEqual(exc.path, 'path')
1343
1344        # Reset not specified attributes
1345        exc.__init__()
1346        self.assertEqual(exc.args, ())
1347        self.assertEqual(exc.msg, None)
1348        self.assertEqual(exc.name, None)
1349        self.assertEqual(exc.path, None)
1350
1351    def test_non_str_argument(self):
1352        # Issue #15778
1353        with check_warnings(('', BytesWarning), quiet=True):
1354            arg = b'abc'
1355            exc = ImportError(arg)
1356            self.assertEqual(str(arg), str(exc))
1357
1358    def test_copy_pickle(self):
1359        for kwargs in (dict(),
1360                       dict(name='somename'),
1361                       dict(path='somepath'),
1362                       dict(name='somename', path='somepath')):
1363            orig = ImportError('test', **kwargs)
1364            for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1365                exc = pickle.loads(pickle.dumps(orig, proto))
1366                self.assertEqual(exc.args, ('test',))
1367                self.assertEqual(exc.msg, 'test')
1368                self.assertEqual(exc.name, orig.name)
1369                self.assertEqual(exc.path, orig.path)
1370            for c in copy.copy, copy.deepcopy:
1371                exc = c(orig)
1372                self.assertEqual(exc.args, ('test',))
1373                self.assertEqual(exc.msg, 'test')
1374                self.assertEqual(exc.name, orig.name)
1375                self.assertEqual(exc.path, orig.path)
1376
1377
1378if __name__ == '__main__':
1379    unittest.main()
1380