• 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
10from codecs import BOM_UTF8
11from itertools import product
12from textwrap import dedent
13
14from test.support import (captured_stderr, check_impl_detail,
15                          cpython_only, gc_collect,
16                          no_tracing, script_helper,
17                          SuppressCrashReport,
18                          force_not_colorized)
19from test.support.import_helper import import_module
20from test.support.os_helper import TESTFN, unlink
21from test.support.warnings_helper import check_warnings
22from test import support
23
24try:
25    import _testcapi
26    from _testcapi import INT_MAX
27except ImportError:
28    _testcapi = None
29    INT_MAX = 2**31 - 1
30
31
32class NaiveException(Exception):
33    def __init__(self, x):
34        self.x = x
35
36class SlottedNaiveException(Exception):
37    __slots__ = ('x',)
38    def __init__(self, x):
39        self.x = x
40
41class BrokenStrException(Exception):
42    def __str__(self):
43        raise Exception("str() is broken")
44
45# XXX This is not really enough, each *operation* should be tested!
46
47
48class ExceptionTests(unittest.TestCase):
49
50    def raise_catch(self, exc, excname):
51        with self.subTest(exc=exc, excname=excname):
52            try:
53                raise exc("spam")
54            except exc as err:
55                buf1 = str(err)
56            try:
57                raise exc("spam")
58            except exc as err:
59                buf2 = str(err)
60            self.assertEqual(buf1, buf2)
61            self.assertEqual(exc.__name__, excname)
62
63    def testRaising(self):
64        self.raise_catch(AttributeError, "AttributeError")
65        self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")
66
67        self.raise_catch(EOFError, "EOFError")
68        fp = open(TESTFN, 'w', encoding="utf-8")
69        fp.close()
70        fp = open(TESTFN, 'r', encoding="utf-8")
71        savestdin = sys.stdin
72        try:
73            try:
74                import marshal
75                marshal.loads(b'')
76            except EOFError:
77                pass
78        finally:
79            sys.stdin = savestdin
80            fp.close()
81            unlink(TESTFN)
82
83        self.raise_catch(OSError, "OSError")
84        self.assertRaises(OSError, open, 'this file does not exist', 'r')
85
86        self.raise_catch(ImportError, "ImportError")
87        self.assertRaises(ImportError, __import__, "undefined_module")
88
89        self.raise_catch(IndexError, "IndexError")
90        x = []
91        self.assertRaises(IndexError, x.__getitem__, 10)
92
93        self.raise_catch(KeyError, "KeyError")
94        x = {}
95        self.assertRaises(KeyError, x.__getitem__, 'key')
96
97        self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")
98
99        self.raise_catch(MemoryError, "MemoryError")
100
101        self.raise_catch(NameError, "NameError")
102        try: x = undefined_variable
103        except NameError: pass
104
105        self.raise_catch(OverflowError, "OverflowError")
106        x = 1
107        for dummy in range(128):
108            x += x  # this simply shouldn't blow up
109
110        self.raise_catch(RuntimeError, "RuntimeError")
111        self.raise_catch(RecursionError, "RecursionError")
112
113        self.raise_catch(SyntaxError, "SyntaxError")
114        try: exec('/\n')
115        except SyntaxError: pass
116
117        self.raise_catch(IndentationError, "IndentationError")
118
119        self.raise_catch(TabError, "TabError")
120        try: compile("try:\n\t1/0\n    \t1/0\nfinally:\n pass\n",
121                     '<string>', 'exec')
122        except TabError: pass
123        else: self.fail("TabError not raised")
124
125        self.raise_catch(SystemError, "SystemError")
126
127        self.raise_catch(SystemExit, "SystemExit")
128        self.assertRaises(SystemExit, sys.exit, 0)
129
130        self.raise_catch(TypeError, "TypeError")
131        try: [] + ()
132        except TypeError: pass
133
134        self.raise_catch(ValueError, "ValueError")
135        self.assertRaises(ValueError, chr, 17<<16)
136
137        self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
138        try: x = 1/0
139        except ZeroDivisionError: pass
140
141        self.raise_catch(Exception, "Exception")
142        try: x = 1/0
143        except Exception as e: pass
144
145        self.raise_catch(StopAsyncIteration, "StopAsyncIteration")
146
147    def testSyntaxErrorMessage(self):
148        # make sure the right exception message is raised for each of
149        # these code fragments
150
151        def ckmsg(src, msg):
152            with self.subTest(src=src, msg=msg):
153                try:
154                    compile(src, '<fragment>', 'exec')
155                except SyntaxError as e:
156                    if e.msg != msg:
157                        self.fail("expected %s, got %s" % (msg, e.msg))
158                else:
159                    self.fail("failed to get expected SyntaxError")
160
161        s = '''if 1:
162        try:
163            continue
164        except:
165            pass'''
166
167        ckmsg(s, "'continue' not properly in loop")
168        ckmsg("continue\n", "'continue' not properly in loop")
169        ckmsg("f'{6 0}'", "invalid syntax. Perhaps you forgot a comma?")
170
171    def testSyntaxErrorMissingParens(self):
172        def ckmsg(src, msg, exception=SyntaxError):
173            try:
174                compile(src, '<fragment>', 'exec')
175            except exception as e:
176                if e.msg != msg:
177                    self.fail("expected %s, got %s" % (msg, e.msg))
178            else:
179                self.fail("failed to get expected SyntaxError")
180
181        s = '''print "old style"'''
182        ckmsg(s, "Missing parentheses in call to 'print'. Did you mean print(...)?")
183
184        s = '''print "old style",'''
185        ckmsg(s, "Missing parentheses in call to 'print'. Did you mean print(...)?")
186
187        s = 'print f(a+b,c)'
188        ckmsg(s, "Missing parentheses in call to 'print'. Did you mean print(...)?")
189
190        s = '''exec "old style"'''
191        ckmsg(s, "Missing parentheses in call to 'exec'. Did you mean exec(...)?")
192
193        s = 'exec f(a+b,c)'
194        ckmsg(s, "Missing parentheses in call to 'exec'. Did you mean exec(...)?")
195
196        # Check that we don't incorrectly identify '(...)' as an expression to the right
197        # of 'print'
198
199        s = 'print (a+b,c) $ 42'
200        ckmsg(s, "invalid syntax")
201
202        s = 'exec (a+b,c) $ 42'
203        ckmsg(s, "invalid syntax")
204
205        # should not apply to subclasses, see issue #31161
206        s = '''if True:\nprint "No indent"'''
207        ckmsg(s, "expected an indented block after 'if' statement on line 1", IndentationError)
208
209        s = '''if True:\n        print()\n\texec "mixed tabs and spaces"'''
210        ckmsg(s, "inconsistent use of tabs and spaces in indentation", TabError)
211
212    def check(self, src, lineno, offset, end_lineno=None, end_offset=None, encoding='utf-8'):
213        with self.subTest(source=src, lineno=lineno, offset=offset):
214            with self.assertRaises(SyntaxError) as cm:
215                compile(src, '<fragment>', 'exec')
216            self.assertEqual(cm.exception.lineno, lineno)
217            self.assertEqual(cm.exception.offset, offset)
218            if end_lineno is not None:
219                self.assertEqual(cm.exception.end_lineno, end_lineno)
220            if end_offset is not None:
221                self.assertEqual(cm.exception.end_offset, end_offset)
222
223            if cm.exception.text is not None:
224                if not isinstance(src, str):
225                    src = src.decode(encoding, 'replace')
226                line = src.split('\n')[lineno-1]
227                self.assertIn(line, cm.exception.text)
228
229    def test_error_offset_continuation_characters(self):
230        check = self.check
231        check('"\\\n"(1 for c in I,\\\n\\', 2, 2)
232
233    def testSyntaxErrorOffset(self):
234        check = self.check
235        check('def fact(x):\n\treturn x!\n', 2, 10)
236        check('1 +\n', 1, 4)
237        check('def spam():\n  print(1)\n print(2)', 3, 10)
238        check('Python = "Python" +', 1, 20)
239        check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20)
240        check(b'# -*- coding: cp1251 -*-\nPython = "\xcf\xb3\xf2\xee\xed" +',
241              2, 19, encoding='cp1251')
242        check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 10)
243        check('x = "a', 1, 5)
244        check('lambda x: x = 2', 1, 1)
245        check('f{a + b + c}', 1, 2)
246        check('[file for str(file) in []\n]', 1, 11)
247        check('a = « hello » « world »', 1, 5)
248        check('[\nfile\nfor str(file)\nin\n[]\n]', 3, 5)
249        check('[file for\n str(file) in []]', 2, 2)
250        check("ages = {'Alice'=22, 'Bob'=23}", 1, 9)
251        check('match ...:\n    case {**rest, "key": value}:\n        ...', 2, 19)
252        check("[a b c d e f]", 1, 2)
253        check("for x yfff:", 1, 7)
254        check("f(a for a in b, c)", 1, 3, 1, 15)
255        check("f(a for a in b if a, c)", 1, 3, 1, 20)
256        check("f(a, b for b in c)", 1, 6, 1, 18)
257        check("f(a, b for b in c, d)", 1, 6, 1, 18)
258
259        # Errors thrown by compile.c
260        check('class foo:return 1', 1, 11)
261        check('def f():\n  continue', 2, 3)
262        check('def f():\n  break', 2, 3)
263        check('try:\n  pass\nexcept:\n  pass\nexcept ValueError:\n  pass', 3, 1)
264        check('try:\n  pass\nexcept*:\n  pass', 3, 8)
265        check('try:\n  pass\nexcept*:\n  pass\nexcept* ValueError:\n  pass', 3, 8)
266
267        # Errors thrown by the tokenizer
268        check('(0x+1)', 1, 3)
269        check('x = 0xI', 1, 6)
270        check('0010 + 2', 1, 1)
271        check('x = 32e-+4', 1, 8)
272        check('x = 0o9', 1, 7)
273        check('\u03b1 = 0xI', 1, 6)
274        check(b'\xce\xb1 = 0xI', 1, 6)
275        check(b'# -*- coding: iso8859-7 -*-\n\xe1 = 0xI', 2, 6,
276              encoding='iso8859-7')
277        check(b"""if 1:
278            def foo():
279                '''
280
281            def bar():
282                pass
283
284            def baz():
285                '''quux'''
286            """, 9, 24)
287        check("pass\npass\npass\n(1+)\npass\npass\npass", 4, 4)
288        check("(1+)", 1, 4)
289        check("[interesting\nfoo()\n", 1, 1)
290        check(b"\xef\xbb\xbf#coding: utf8\nprint('\xe6\x88\x91')\n", 0, -1)
291        check("""f'''
292            {
293            (123_a)
294            }'''""", 3, 17)
295        check("""f'''
296            {
297            f\"\"\"
298            {
299            (123_a)
300            }
301            \"\"\"
302            }'''""", 5, 17)
303        check('''f"""
304
305
306            {
307            6
308            0="""''', 5, 13)
309        check('b"fooжжж"'.encode(), 1, 1, 1, 10)
310
311        # Errors thrown by symtable.c
312        check('x = [(yield i) for i in range(3)]', 1, 7)
313        check('def f():\n  from _ import *', 2, 17)
314        check('def f(x, x):\n  pass', 1, 10)
315        check('{i for i in range(5) if (j := 0) for j in range(5)}', 1, 38)
316        check('def f(x):\n  nonlocal x', 2, 3)
317        check('def f(x):\n  x = 1\n  global x', 3, 3)
318        check('nonlocal x', 1, 1)
319        check('def f():\n  global x\n  nonlocal x', 2, 3)
320
321        # Errors thrown by future.c
322        check('from __future__ import doesnt_exist', 1, 24)
323        check('from __future__ import braces', 1, 24)
324        check('x=1\nfrom __future__ import division', 2, 1)
325        check('foo(1=2)', 1, 5)
326        check('def f():\n  x, y: int', 2, 3)
327        check('[*x for x in xs]', 1, 2)
328        check('foo(x for x in range(10), 100)', 1, 5)
329        check('for 1 in []: pass', 1, 5)
330        check('(yield i) = 2', 1, 2)
331        check('def f(*):\n  pass', 1, 7)
332
333    @unittest.skipIf(INT_MAX >= sys.maxsize, "Downcasting to int is safe for col_offset")
334    @support.requires_resource('cpu')
335    @support.bigmemtest(INT_MAX, memuse=2, dry_run=False)
336    def testMemoryErrorBigSource(self, size):
337        src = b"if True:\n%*s" % (size, b"pass")
338        with self.assertRaisesRegex(OverflowError, "Parser column offset overflow"):
339            compile(src, '<fragment>', 'exec')
340
341    @cpython_only
342    def testSettingException(self):
343        # test that setting an exception at the C level works even if the
344        # exception object can't be constructed.
345
346        class BadException(Exception):
347            def __init__(self_):
348                raise RuntimeError("can't instantiate BadException")
349
350        class InvalidException:
351            pass
352
353        @unittest.skipIf(_testcapi is None, "requires _testcapi")
354        def test_capi1():
355            try:
356                _testcapi.raise_exception(BadException, 1)
357            except TypeError as err:
358                co = err.__traceback__.tb_frame.f_code
359                self.assertEqual(co.co_name, "test_capi1")
360                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
361            else:
362                self.fail("Expected exception")
363
364        @unittest.skipIf(_testcapi is None, "requires _testcapi")
365        def test_capi2():
366            try:
367                _testcapi.raise_exception(BadException, 0)
368            except RuntimeError as err:
369                tb = err.__traceback__.tb_next
370                co = tb.tb_frame.f_code
371                self.assertEqual(co.co_name, "__init__")
372                self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
373                co2 = tb.tb_frame.f_back.f_code
374                self.assertEqual(co2.co_name, "test_capi2")
375            else:
376                self.fail("Expected exception")
377
378        @unittest.skipIf(_testcapi is None, "requires _testcapi")
379        def test_capi3():
380            self.assertRaises(SystemError, _testcapi.raise_exception,
381                              InvalidException, 1)
382
383        test_capi1()
384        test_capi2()
385        test_capi3()
386
387    def test_WindowsError(self):
388        try:
389            WindowsError
390        except NameError:
391            pass
392        else:
393            self.assertIs(WindowsError, OSError)
394            self.assertEqual(str(OSError(1001)), "1001")
395            self.assertEqual(str(OSError(1001, "message")),
396                             "[Errno 1001] message")
397            # POSIX errno (9 aka EBADF) is untranslated
398            w = OSError(9, 'foo', 'bar')
399            self.assertEqual(w.errno, 9)
400            self.assertEqual(w.winerror, None)
401            self.assertEqual(str(w), "[Errno 9] foo: 'bar'")
402            # ERROR_PATH_NOT_FOUND (win error 3) becomes ENOENT (2)
403            w = OSError(0, 'foo', 'bar', 3)
404            self.assertEqual(w.errno, 2)
405            self.assertEqual(w.winerror, 3)
406            self.assertEqual(w.strerror, 'foo')
407            self.assertEqual(w.filename, 'bar')
408            self.assertEqual(w.filename2, None)
409            self.assertEqual(str(w), "[WinError 3] foo: 'bar'")
410            # Unknown win error becomes EINVAL (22)
411            w = OSError(0, 'foo', None, 1001)
412            self.assertEqual(w.errno, 22)
413            self.assertEqual(w.winerror, 1001)
414            self.assertEqual(w.strerror, 'foo')
415            self.assertEqual(w.filename, None)
416            self.assertEqual(w.filename2, None)
417            self.assertEqual(str(w), "[WinError 1001] foo")
418            # Non-numeric "errno"
419            w = OSError('bar', 'foo')
420            self.assertEqual(w.errno, 'bar')
421            self.assertEqual(w.winerror, None)
422            self.assertEqual(w.strerror, 'foo')
423            self.assertEqual(w.filename, None)
424            self.assertEqual(w.filename2, None)
425
426    @unittest.skipUnless(sys.platform == 'win32',
427                         'test specific to Windows')
428    def test_windows_message(self):
429        """Should fill in unknown error code in Windows error message"""
430        ctypes = import_module('ctypes')
431        # this error code has no message, Python formats it as hexadecimal
432        code = 3765269347
433        with self.assertRaisesRegex(OSError, 'Windows Error 0x%x' % code):
434            ctypes.pythonapi.PyErr_SetFromWindowsErr(code)
435
436    def testAttributes(self):
437        # test that exception attributes are happy
438
439        exceptionList = [
440            (BaseException, (), {}, {'args' : ()}),
441            (BaseException, (1, ), {}, {'args' : (1,)}),
442            (BaseException, ('foo',), {},
443                {'args' : ('foo',)}),
444            (BaseException, ('foo', 1), {},
445                {'args' : ('foo', 1)}),
446            (SystemExit, ('foo',), {},
447                {'args' : ('foo',), 'code' : 'foo'}),
448            (OSError, ('foo',), {},
449                {'args' : ('foo',), 'filename' : None, 'filename2' : None,
450                 'errno' : None, 'strerror' : None}),
451            (OSError, ('foo', 'bar'), {},
452                {'args' : ('foo', 'bar'),
453                 'filename' : None, 'filename2' : None,
454                 'errno' : 'foo', 'strerror' : 'bar'}),
455            (OSError, ('foo', 'bar', 'baz'), {},
456                {'args' : ('foo', 'bar'),
457                 'filename' : 'baz', 'filename2' : None,
458                 'errno' : 'foo', 'strerror' : 'bar'}),
459            (OSError, ('foo', 'bar', 'baz', None, 'quux'), {},
460                {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}),
461            (OSError, ('errnoStr', 'strErrorStr', 'filenameStr'), {},
462                {'args' : ('errnoStr', 'strErrorStr'),
463                 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
464                 'filename' : 'filenameStr'}),
465            (OSError, (1, 'strErrorStr', 'filenameStr'), {},
466                {'args' : (1, 'strErrorStr'), 'errno' : 1,
467                 'strerror' : 'strErrorStr',
468                 'filename' : 'filenameStr', 'filename2' : None}),
469            (SyntaxError, (), {}, {'msg' : None, 'text' : None,
470                'filename' : None, 'lineno' : None, 'offset' : None,
471                'end_offset': None, 'print_file_and_line' : None}),
472            (SyntaxError, ('msgStr',), {},
473                {'args' : ('msgStr',), 'text' : None,
474                 'print_file_and_line' : None, 'msg' : 'msgStr',
475                 'filename' : None, 'lineno' : None, 'offset' : None,
476                 'end_offset': None}),
477            (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
478                           'textStr', 'endLinenoStr', 'endOffsetStr')), {},
479                {'offset' : 'offsetStr', 'text' : 'textStr',
480                 'args' : ('msgStr', ('filenameStr', 'linenoStr',
481                                      'offsetStr', 'textStr',
482                                      'endLinenoStr', 'endOffsetStr')),
483                 'print_file_and_line' : None, 'msg' : 'msgStr',
484                 'filename' : 'filenameStr', 'lineno' : 'linenoStr',
485                 'end_lineno': 'endLinenoStr', 'end_offset': 'endOffsetStr'}),
486            (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
487                           'textStr', 'endLinenoStr', 'endOffsetStr',
488                           'print_file_and_lineStr'), {},
489                {'text' : None,
490                 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
491                           'textStr', 'endLinenoStr', 'endOffsetStr',
492                           'print_file_and_lineStr'),
493                 'print_file_and_line' : None, 'msg' : 'msgStr',
494                 'filename' : None, 'lineno' : None, 'offset' : None,
495                 'end_lineno': None, 'end_offset': None}),
496            (UnicodeError, (), {}, {'args' : (),}),
497            (UnicodeEncodeError, ('ascii', 'a', 0, 1,
498                                  'ordinal not in range'), {},
499                {'args' : ('ascii', 'a', 0, 1,
500                                           'ordinal not in range'),
501                 'encoding' : 'ascii', 'object' : 'a',
502                 'start' : 0, 'reason' : 'ordinal not in range'}),
503            (UnicodeDecodeError, ('ascii', bytearray(b'\xff'), 0, 1,
504                                  'ordinal not in range'), {},
505                {'args' : ('ascii', bytearray(b'\xff'), 0, 1,
506                                           'ordinal not in range'),
507                 'encoding' : 'ascii', 'object' : b'\xff',
508                 'start' : 0, 'reason' : 'ordinal not in range'}),
509            (UnicodeDecodeError, ('ascii', b'\xff', 0, 1,
510                                  'ordinal not in range'), {},
511                {'args' : ('ascii', b'\xff', 0, 1,
512                                           'ordinal not in range'),
513                 'encoding' : 'ascii', 'object' : b'\xff',
514                 'start' : 0, 'reason' : 'ordinal not in range'}),
515            (UnicodeTranslateError, ("\u3042", 0, 1, "ouch"), {},
516                {'args' : ('\u3042', 0, 1, 'ouch'),
517                 'object' : '\u3042', 'reason' : 'ouch',
518                 'start' : 0, 'end' : 1}),
519            (NaiveException, ('foo',), {},
520                {'args': ('foo',), 'x': 'foo'}),
521            (SlottedNaiveException, ('foo',), {},
522                {'args': ('foo',), 'x': 'foo'}),
523            (AttributeError, ('foo',), dict(name='name', obj='obj'),
524                dict(args=('foo',), name='name', obj='obj')),
525        ]
526        try:
527            # More tests are in test_WindowsError
528            exceptionList.append(
529                (WindowsError, (1, 'strErrorStr', 'filenameStr'), {},
530                    {'args' : (1, 'strErrorStr'),
531                     'strerror' : 'strErrorStr', 'winerror' : None,
532                     'errno' : 1,
533                     'filename' : 'filenameStr', 'filename2' : None})
534            )
535        except NameError:
536            pass
537
538        for exc, args, kwargs, expected in exceptionList:
539            try:
540                e = exc(*args, **kwargs)
541            except:
542                print(f"\nexc={exc!r}, args={args!r}", file=sys.stderr)
543                # raise
544            else:
545                # Verify module name
546                if not type(e).__name__.endswith('NaiveException'):
547                    self.assertEqual(type(e).__module__, 'builtins')
548                # Verify no ref leaks in Exc_str()
549                s = str(e)
550                for checkArgName in expected:
551                    value = getattr(e, checkArgName)
552                    self.assertEqual(repr(value),
553                                     repr(expected[checkArgName]),
554                                     '%r.%s == %r, expected %r' % (
555                                     e, checkArgName,
556                                     value, expected[checkArgName]))
557
558                # test for pickling support
559                for p in [pickle]:
560                    for protocol in range(p.HIGHEST_PROTOCOL + 1):
561                        s = p.dumps(e, protocol)
562                        new = p.loads(s)
563                        for checkArgName in expected:
564                            got = repr(getattr(new, checkArgName))
565                            if exc == AttributeError and checkArgName == 'obj':
566                                # See GH-103352, we're not pickling
567                                # obj at this point. So verify it's None.
568                                want = repr(None)
569                            else:
570                                want = repr(expected[checkArgName])
571                            self.assertEqual(got, want,
572                                             'pickled "%r", attribute "%s' %
573                                             (e, checkArgName))
574
575    def test_setstate(self):
576        e = Exception(42)
577        e.blah = 53
578        self.assertEqual(e.args, (42,))
579        self.assertEqual(e.blah, 53)
580        self.assertRaises(AttributeError, getattr, e, 'a')
581        self.assertRaises(AttributeError, getattr, e, 'b')
582        e.__setstate__({'a': 1 , 'b': 2})
583        self.assertEqual(e.args, (42,))
584        self.assertEqual(e.blah, 53)
585        self.assertEqual(e.a, 1)
586        self.assertEqual(e.b, 2)
587        e.__setstate__({'a': 11, 'args': (1,2,3), 'blah': 35})
588        self.assertEqual(e.args, (1,2,3))
589        self.assertEqual(e.blah, 35)
590        self.assertEqual(e.a, 11)
591        self.assertEqual(e.b, 2)
592
593    def test_invalid_setstate(self):
594        e = Exception(42)
595        with self.assertRaisesRegex(TypeError, "state is not a dictionary"):
596            e.__setstate__(42)
597
598    def test_notes(self):
599        for e in [BaseException(1), Exception(2), ValueError(3)]:
600            with self.subTest(e=e):
601                self.assertFalse(hasattr(e, '__notes__'))
602                e.add_note("My Note")
603                self.assertEqual(e.__notes__, ["My Note"])
604
605                with self.assertRaises(TypeError):
606                    e.add_note(42)
607                self.assertEqual(e.__notes__, ["My Note"])
608
609                e.add_note("Your Note")
610                self.assertEqual(e.__notes__, ["My Note", "Your Note"])
611
612                del e.__notes__
613                self.assertFalse(hasattr(e, '__notes__'))
614
615                e.add_note("Our Note")
616                self.assertEqual(e.__notes__, ["Our Note"])
617
618                e.__notes__ = 42
619                self.assertEqual(e.__notes__, 42)
620
621                with self.assertRaises(TypeError):
622                    e.add_note("will not work")
623                self.assertEqual(e.__notes__, 42)
624
625    def testWithTraceback(self):
626        try:
627            raise IndexError(4)
628        except Exception as e:
629            tb = e.__traceback__
630
631        e = BaseException().with_traceback(tb)
632        self.assertIsInstance(e, BaseException)
633        self.assertEqual(e.__traceback__, tb)
634
635        e = IndexError(5).with_traceback(tb)
636        self.assertIsInstance(e, IndexError)
637        self.assertEqual(e.__traceback__, tb)
638
639        class MyException(Exception):
640            pass
641
642        e = MyException().with_traceback(tb)
643        self.assertIsInstance(e, MyException)
644        self.assertEqual(e.__traceback__, tb)
645
646    def testInvalidTraceback(self):
647        try:
648            Exception().__traceback__ = 5
649        except TypeError as e:
650            self.assertIn("__traceback__ must be a traceback", str(e))
651        else:
652            self.fail("No exception raised")
653
654    def test_invalid_setattr(self):
655        TE = TypeError
656        exc = Exception()
657        msg = "'int' object is not iterable"
658        self.assertRaisesRegex(TE, msg, setattr, exc, 'args', 1)
659        msg = "__traceback__ must be a traceback or None"
660        self.assertRaisesRegex(TE, msg, setattr, exc, '__traceback__', 1)
661        msg = "exception cause must be None or derive from BaseException"
662        self.assertRaisesRegex(TE, msg, setattr, exc, '__cause__', 1)
663        msg = "exception context must be None or derive from BaseException"
664        self.assertRaisesRegex(TE, msg, setattr, exc, '__context__', 1)
665
666    def test_invalid_delattr(self):
667        TE = TypeError
668        try:
669            raise IndexError(4)
670        except Exception as e:
671            exc = e
672
673        msg = "may not be deleted"
674        self.assertRaisesRegex(TE, msg, delattr, exc, 'args')
675        self.assertRaisesRegex(TE, msg, delattr, exc, '__traceback__')
676        self.assertRaisesRegex(TE, msg, delattr, exc, '__cause__')
677        self.assertRaisesRegex(TE, msg, delattr, exc, '__context__')
678
679    def testNoneClearsTracebackAttr(self):
680        try:
681            raise IndexError(4)
682        except Exception as e:
683            tb = e.__traceback__
684
685        e = Exception()
686        e.__traceback__ = tb
687        e.__traceback__ = None
688        self.assertEqual(e.__traceback__, None)
689
690    def testChainingAttrs(self):
691        e = Exception()
692        self.assertIsNone(e.__context__)
693        self.assertIsNone(e.__cause__)
694
695        e = TypeError()
696        self.assertIsNone(e.__context__)
697        self.assertIsNone(e.__cause__)
698
699        class MyException(OSError):
700            pass
701
702        e = MyException()
703        self.assertIsNone(e.__context__)
704        self.assertIsNone(e.__cause__)
705
706    def testChainingDescriptors(self):
707        try:
708            raise Exception()
709        except Exception as exc:
710            e = exc
711
712        self.assertIsNone(e.__context__)
713        self.assertIsNone(e.__cause__)
714        self.assertFalse(e.__suppress_context__)
715
716        e.__context__ = NameError()
717        e.__cause__ = None
718        self.assertIsInstance(e.__context__, NameError)
719        self.assertIsNone(e.__cause__)
720        self.assertTrue(e.__suppress_context__)
721        e.__suppress_context__ = False
722        self.assertFalse(e.__suppress_context__)
723
724    def testKeywordArgs(self):
725        # test that builtin exception don't take keyword args,
726        # but user-defined subclasses can if they want
727        self.assertRaises(TypeError, BaseException, a=1)
728
729        class DerivedException(BaseException):
730            def __init__(self, fancy_arg):
731                BaseException.__init__(self)
732                self.fancy_arg = fancy_arg
733
734        x = DerivedException(fancy_arg=42)
735        self.assertEqual(x.fancy_arg, 42)
736
737    @no_tracing
738    def testInfiniteRecursion(self):
739        def f():
740            return f()
741        self.assertRaises(RecursionError, f)
742
743        def g():
744            try:
745                return g()
746            except ValueError:
747                return -1
748        self.assertRaises(RecursionError, g)
749
750    def test_str(self):
751        # Make sure both instances and classes have a str representation.
752        self.assertTrue(str(Exception))
753        self.assertTrue(str(Exception('a')))
754        self.assertTrue(str(Exception('a', 'b')))
755
756    def test_exception_cleanup_names(self):
757        # Make sure the local variable bound to the exception instance by
758        # an "except" statement is only visible inside the except block.
759        try:
760            raise Exception()
761        except Exception as e:
762            self.assertIsInstance(e, Exception)
763        self.assertNotIn('e', locals())
764        with self.assertRaises(UnboundLocalError):
765            e
766
767    def test_exception_cleanup_names2(self):
768        # Make sure the cleanup doesn't break if the variable is explicitly deleted.
769        try:
770            raise Exception()
771        except Exception as e:
772            self.assertIsInstance(e, Exception)
773            del e
774        self.assertNotIn('e', locals())
775        with self.assertRaises(UnboundLocalError):
776            e
777
778    def testExceptionCleanupState(self):
779        # Make sure exception state is cleaned up as soon as the except
780        # block is left. See #2507
781
782        class MyException(Exception):
783            def __init__(self, obj):
784                self.obj = obj
785        class MyObj:
786            pass
787
788        def inner_raising_func():
789            # Create some references in exception value and traceback
790            local_ref = obj
791            raise MyException(obj)
792
793        # Qualified "except" with "as"
794        obj = MyObj()
795        wr = weakref.ref(obj)
796        try:
797            inner_raising_func()
798        except MyException as e:
799            pass
800        obj = None
801        gc_collect()  # For PyPy or other GCs.
802        obj = wr()
803        self.assertIsNone(obj)
804
805        # Qualified "except" without "as"
806        obj = MyObj()
807        wr = weakref.ref(obj)
808        try:
809            inner_raising_func()
810        except MyException:
811            pass
812        obj = None
813        gc_collect()  # For PyPy or other GCs.
814        obj = wr()
815        self.assertIsNone(obj)
816
817        # Bare "except"
818        obj = MyObj()
819        wr = weakref.ref(obj)
820        try:
821            inner_raising_func()
822        except:
823            pass
824        obj = None
825        gc_collect()  # For PyPy or other GCs.
826        obj = wr()
827        self.assertIsNone(obj)
828
829        # "except" with premature block leave
830        obj = MyObj()
831        wr = weakref.ref(obj)
832        for i in [0]:
833            try:
834                inner_raising_func()
835            except:
836                break
837        obj = None
838        gc_collect()  # For PyPy or other GCs.
839        obj = wr()
840        self.assertIsNone(obj)
841
842        # "except" block raising another exception
843        obj = MyObj()
844        wr = weakref.ref(obj)
845        try:
846            try:
847                inner_raising_func()
848            except:
849                raise KeyError
850        except KeyError as e:
851            # We want to test that the except block above got rid of
852            # the exception raised in inner_raising_func(), but it
853            # also ends up in the __context__ of the KeyError, so we
854            # must clear the latter manually for our test to succeed.
855            e.__context__ = None
856            obj = None
857            gc_collect()  # For PyPy or other GCs.
858            obj = wr()
859            # guarantee no ref cycles on CPython (don't gc_collect)
860            if check_impl_detail(cpython=False):
861                gc_collect()
862            self.assertIsNone(obj)
863
864        # Some complicated construct
865        obj = MyObj()
866        wr = weakref.ref(obj)
867        try:
868            inner_raising_func()
869        except MyException:
870            try:
871                try:
872                    raise
873                finally:
874                    raise
875            except MyException:
876                pass
877        obj = None
878        if check_impl_detail(cpython=False):
879            gc_collect()
880        obj = wr()
881        self.assertIsNone(obj)
882
883        # Inside an exception-silencing "with" block
884        class Context:
885            def __enter__(self):
886                return self
887            def __exit__ (self, exc_type, exc_value, exc_tb):
888                return True
889        obj = MyObj()
890        wr = weakref.ref(obj)
891        with Context():
892            inner_raising_func()
893        obj = None
894        if check_impl_detail(cpython=False):
895            gc_collect()
896        obj = wr()
897        self.assertIsNone(obj)
898
899    def test_exception_target_in_nested_scope(self):
900        # issue 4617: This used to raise a SyntaxError
901        # "can not delete variable 'e' referenced in nested scope"
902        def print_error():
903            e
904        try:
905            something
906        except Exception as e:
907            print_error()
908            # implicit "del e" here
909
910    def test_generator_leaking(self):
911        # Test that generator exception state doesn't leak into the calling
912        # frame
913        def yield_raise():
914            try:
915                raise KeyError("caught")
916            except KeyError:
917                yield sys.exception()
918                yield sys.exception()
919            yield sys.exception()
920        g = yield_raise()
921        self.assertIsInstance(next(g), KeyError)
922        self.assertIsNone(sys.exception())
923        self.assertIsInstance(next(g), KeyError)
924        self.assertIsNone(sys.exception())
925        self.assertIsNone(next(g))
926
927        # Same test, but inside an exception handler
928        try:
929            raise TypeError("foo")
930        except TypeError:
931            g = yield_raise()
932            self.assertIsInstance(next(g), KeyError)
933            self.assertIsInstance(sys.exception(), TypeError)
934            self.assertIsInstance(next(g), KeyError)
935            self.assertIsInstance(sys.exception(), TypeError)
936            self.assertIsInstance(next(g), TypeError)
937            del g
938            self.assertIsInstance(sys.exception(), TypeError)
939
940    def test_generator_leaking2(self):
941        # See issue 12475.
942        def g():
943            yield
944        try:
945            raise RuntimeError
946        except RuntimeError:
947            it = g()
948            next(it)
949        try:
950            next(it)
951        except StopIteration:
952            pass
953        self.assertIsNone(sys.exception())
954
955    def test_generator_leaking3(self):
956        # See issue #23353.  When gen.throw() is called, the caller's
957        # exception state should be save and restored.
958        def g():
959            try:
960                yield
961            except ZeroDivisionError:
962                yield sys.exception()
963        it = g()
964        next(it)
965        try:
966            1/0
967        except ZeroDivisionError as e:
968            self.assertIs(sys.exception(), e)
969            gen_exc = it.throw(e)
970            self.assertIs(sys.exception(), e)
971            self.assertIs(gen_exc, e)
972        self.assertIsNone(sys.exception())
973
974    def test_generator_leaking4(self):
975        # See issue #23353.  When an exception is raised by a generator,
976        # the caller's exception state should still be restored.
977        def g():
978            try:
979                1/0
980            except ZeroDivisionError:
981                yield sys.exception()
982                raise
983        it = g()
984        try:
985            raise TypeError
986        except TypeError:
987            # The caller's exception state (TypeError) is temporarily
988            # saved in the generator.
989            tp = type(next(it))
990        self.assertIs(tp, ZeroDivisionError)
991        try:
992            next(it)
993            # We can't check it immediately, but while next() returns
994            # with an exception, it shouldn't have restored the old
995            # exception state (TypeError).
996        except ZeroDivisionError as e:
997            self.assertIs(sys.exception(), e)
998        # We used to find TypeError here.
999        self.assertIsNone(sys.exception())
1000
1001    def test_generator_doesnt_retain_old_exc(self):
1002        def g():
1003            self.assertIsInstance(sys.exception(), RuntimeError)
1004            yield
1005            self.assertIsNone(sys.exception())
1006        it = g()
1007        try:
1008            raise RuntimeError
1009        except RuntimeError:
1010            next(it)
1011        self.assertRaises(StopIteration, next, it)
1012
1013    def test_generator_finalizing_and_sys_exception(self):
1014        # See #7173
1015        def simple_gen():
1016            yield 1
1017        def run_gen():
1018            gen = simple_gen()
1019            try:
1020                raise RuntimeError
1021            except RuntimeError:
1022                return next(gen)
1023        run_gen()
1024        gc_collect()
1025        self.assertIsNone(sys.exception())
1026
1027    def _check_generator_cleanup_exc_state(self, testfunc):
1028        # Issue #12791: exception state is cleaned up as soon as a generator
1029        # is closed (reference cycles are broken).
1030        class MyException(Exception):
1031            def __init__(self, obj):
1032                self.obj = obj
1033        class MyObj:
1034            pass
1035
1036        def raising_gen():
1037            try:
1038                raise MyException(obj)
1039            except MyException:
1040                yield
1041
1042        obj = MyObj()
1043        wr = weakref.ref(obj)
1044        g = raising_gen()
1045        next(g)
1046        testfunc(g)
1047        g = obj = None
1048        gc_collect()  # For PyPy or other GCs.
1049        obj = wr()
1050        self.assertIsNone(obj)
1051
1052    def test_generator_throw_cleanup_exc_state(self):
1053        def do_throw(g):
1054            try:
1055                g.throw(RuntimeError())
1056            except RuntimeError:
1057                pass
1058        self._check_generator_cleanup_exc_state(do_throw)
1059
1060    def test_generator_close_cleanup_exc_state(self):
1061        def do_close(g):
1062            g.close()
1063        self._check_generator_cleanup_exc_state(do_close)
1064
1065    def test_generator_del_cleanup_exc_state(self):
1066        def do_del(g):
1067            g = None
1068        self._check_generator_cleanup_exc_state(do_del)
1069
1070    def test_generator_next_cleanup_exc_state(self):
1071        def do_next(g):
1072            try:
1073                next(g)
1074            except StopIteration:
1075                pass
1076            else:
1077                self.fail("should have raised StopIteration")
1078        self._check_generator_cleanup_exc_state(do_next)
1079
1080    def test_generator_send_cleanup_exc_state(self):
1081        def do_send(g):
1082            try:
1083                g.send(None)
1084            except StopIteration:
1085                pass
1086            else:
1087                self.fail("should have raised StopIteration")
1088        self._check_generator_cleanup_exc_state(do_send)
1089
1090    def test_3114(self):
1091        # Bug #3114: in its destructor, MyObject retrieves a pointer to
1092        # obsolete and/or deallocated objects.
1093        class MyObject:
1094            def __del__(self):
1095                nonlocal e
1096                e = sys.exception()
1097        e = ()
1098        try:
1099            raise Exception(MyObject())
1100        except:
1101            pass
1102        gc_collect()  # For PyPy or other GCs.
1103        self.assertIsNone(e)
1104
1105    def test_raise_does_not_create_context_chain_cycle(self):
1106        class A(Exception):
1107            pass
1108        class B(Exception):
1109            pass
1110        class C(Exception):
1111            pass
1112
1113        # Create a context chain:
1114        # C -> B -> A
1115        # Then raise A in context of C.
1116        try:
1117            try:
1118                raise A
1119            except A as a_:
1120                a = a_
1121                try:
1122                    raise B
1123                except B as b_:
1124                    b = b_
1125                    try:
1126                        raise C
1127                    except C as c_:
1128                        c = c_
1129                        self.assertIsInstance(a, A)
1130                        self.assertIsInstance(b, B)
1131                        self.assertIsInstance(c, C)
1132                        self.assertIsNone(a.__context__)
1133                        self.assertIs(b.__context__, a)
1134                        self.assertIs(c.__context__, b)
1135                        raise a
1136        except A as e:
1137            exc = e
1138
1139        # Expect A -> C -> B, without cycle
1140        self.assertIs(exc, a)
1141        self.assertIs(a.__context__, c)
1142        self.assertIs(c.__context__, b)
1143        self.assertIsNone(b.__context__)
1144
1145    def test_no_hang_on_context_chain_cycle1(self):
1146        # See issue 25782. Cycle in context chain.
1147
1148        def cycle():
1149            try:
1150                raise ValueError(1)
1151            except ValueError as ex:
1152                ex.__context__ = ex
1153                raise TypeError(2)
1154
1155        try:
1156            cycle()
1157        except Exception as e:
1158            exc = e
1159
1160        self.assertIsInstance(exc, TypeError)
1161        self.assertIsInstance(exc.__context__, ValueError)
1162        self.assertIs(exc.__context__.__context__, exc.__context__)
1163
1164    def test_no_hang_on_context_chain_cycle2(self):
1165        # See issue 25782. Cycle at head of context chain.
1166
1167        class A(Exception):
1168            pass
1169        class B(Exception):
1170            pass
1171        class C(Exception):
1172            pass
1173
1174        # Context cycle:
1175        # +-----------+
1176        # V           |
1177        # C --> B --> A
1178        with self.assertRaises(C) as cm:
1179            try:
1180                raise A()
1181            except A as _a:
1182                a = _a
1183                try:
1184                    raise B()
1185                except B as _b:
1186                    b = _b
1187                    try:
1188                        raise C()
1189                    except C as _c:
1190                        c = _c
1191                        a.__context__ = c
1192                        raise c
1193
1194        self.assertIs(cm.exception, c)
1195        # Verify the expected context chain cycle
1196        self.assertIs(c.__context__, b)
1197        self.assertIs(b.__context__, a)
1198        self.assertIs(a.__context__, c)
1199
1200    def test_no_hang_on_context_chain_cycle3(self):
1201        # See issue 25782. Longer context chain with cycle.
1202
1203        class A(Exception):
1204            pass
1205        class B(Exception):
1206            pass
1207        class C(Exception):
1208            pass
1209        class D(Exception):
1210            pass
1211        class E(Exception):
1212            pass
1213
1214        # Context cycle:
1215        #             +-----------+
1216        #             V           |
1217        # E --> D --> C --> B --> A
1218        with self.assertRaises(E) as cm:
1219            try:
1220                raise A()
1221            except A as _a:
1222                a = _a
1223                try:
1224                    raise B()
1225                except B as _b:
1226                    b = _b
1227                    try:
1228                        raise C()
1229                    except C as _c:
1230                        c = _c
1231                        a.__context__ = c
1232                        try:
1233                            raise D()
1234                        except D as _d:
1235                            d = _d
1236                            e = E()
1237                            raise e
1238
1239        self.assertIs(cm.exception, e)
1240        # Verify the expected context chain cycle
1241        self.assertIs(e.__context__, d)
1242        self.assertIs(d.__context__, c)
1243        self.assertIs(c.__context__, b)
1244        self.assertIs(b.__context__, a)
1245        self.assertIs(a.__context__, c)
1246
1247    def test_context_of_exception_in_try_and_finally(self):
1248        try:
1249            try:
1250                te = TypeError(1)
1251                raise te
1252            finally:
1253                ve = ValueError(2)
1254                raise ve
1255        except Exception as e:
1256            exc = e
1257
1258        self.assertIs(exc, ve)
1259        self.assertIs(exc.__context__, te)
1260
1261    def test_context_of_exception_in_except_and_finally(self):
1262        try:
1263            try:
1264                te = TypeError(1)
1265                raise te
1266            except:
1267                ve = ValueError(2)
1268                raise ve
1269            finally:
1270                oe = OSError(3)
1271                raise oe
1272        except Exception as e:
1273            exc = e
1274
1275        self.assertIs(exc, oe)
1276        self.assertIs(exc.__context__, ve)
1277        self.assertIs(exc.__context__.__context__, te)
1278
1279    def test_context_of_exception_in_else_and_finally(self):
1280        try:
1281            try:
1282                pass
1283            except:
1284                pass
1285            else:
1286                ve = ValueError(1)
1287                raise ve
1288            finally:
1289                oe = OSError(2)
1290                raise oe
1291        except Exception as e:
1292            exc = e
1293
1294        self.assertIs(exc, oe)
1295        self.assertIs(exc.__context__, ve)
1296
1297    def test_unicode_change_attributes(self):
1298        # See issue 7309. This was a crasher.
1299
1300        u = UnicodeEncodeError('baz', 'xxxxx', 1, 5, 'foo')
1301        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: foo")
1302        u.end = 2
1303        self.assertEqual(str(u), "'baz' codec can't encode character '\\x78' in position 1: foo")
1304        u.end = 5
1305        u.reason = 0x345345345345345345
1306        self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: 965230951443685724997")
1307        u.encoding = 4000
1308        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1-4: 965230951443685724997")
1309        u.start = 1000
1310        self.assertEqual(str(u), "'4000' codec can't encode characters in position 1000-4: 965230951443685724997")
1311
1312        u = UnicodeDecodeError('baz', b'xxxxx', 1, 5, 'foo')
1313        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: foo")
1314        u.end = 2
1315        self.assertEqual(str(u), "'baz' codec can't decode byte 0x78 in position 1: foo")
1316        u.end = 5
1317        u.reason = 0x345345345345345345
1318        self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: 965230951443685724997")
1319        u.encoding = 4000
1320        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1-4: 965230951443685724997")
1321        u.start = 1000
1322        self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1000-4: 965230951443685724997")
1323
1324        u = UnicodeTranslateError('xxxx', 1, 5, 'foo')
1325        self.assertEqual(str(u), "can't translate characters in position 1-4: foo")
1326        u.end = 2
1327        self.assertEqual(str(u), "can't translate character '\\x78' in position 1: foo")
1328        u.end = 5
1329        u.reason = 0x345345345345345345
1330        self.assertEqual(str(u), "can't translate characters in position 1-4: 965230951443685724997")
1331        u.start = 1000
1332        self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997")
1333
1334    def test_unicode_errors_no_object(self):
1335        # See issue #21134.
1336        klasses = UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError
1337        for klass in klasses:
1338            self.assertEqual(str(klass.__new__(klass)), "")
1339
1340    def test_unicode_error_str_does_not_crash(self):
1341        # Test that str(UnicodeError(...)) does not crash.
1342        # See https://github.com/python/cpython/issues/123378.
1343
1344        for start, end, objlen in product(
1345            range(-5, 5),
1346            range(-5, 5),
1347            range(7),
1348        ):
1349            obj = 'a' * objlen
1350            with self.subTest('encode', objlen=objlen, start=start, end=end):
1351                exc = UnicodeEncodeError('utf-8', obj, start, end, '')
1352                self.assertIsInstance(str(exc), str)
1353
1354            with self.subTest('translate', objlen=objlen, start=start, end=end):
1355                exc = UnicodeTranslateError(obj, start, end, '')
1356                self.assertIsInstance(str(exc), str)
1357
1358            encoded = obj.encode()
1359            with self.subTest('decode', objlen=objlen, start=start, end=end):
1360                exc = UnicodeDecodeError('utf-8', encoded, start, end, '')
1361                self.assertIsInstance(str(exc), str)
1362
1363    @no_tracing
1364    def test_badisinstance(self):
1365        # Bug #2542: if issubclass(e, MyException) raises an exception,
1366        # it should be ignored
1367        class Meta(type):
1368            def __subclasscheck__(cls, subclass):
1369                raise ValueError()
1370        class MyException(Exception, metaclass=Meta):
1371            pass
1372
1373        with captured_stderr() as stderr:
1374            try:
1375                raise KeyError()
1376            except MyException as e:
1377                self.fail("exception should not be a MyException")
1378            except KeyError:
1379                pass
1380            except:
1381                self.fail("Should have raised KeyError")
1382            else:
1383                self.fail("Should have raised KeyError")
1384
1385        def g():
1386            try:
1387                return g()
1388            except RecursionError as e:
1389                return e
1390        exc = g()
1391        self.assertIsInstance(exc, RecursionError, type(exc))
1392        self.assertIn("maximum recursion depth exceeded", str(exc))
1393
1394
1395    @cpython_only
1396    @support.requires_resource('cpu')
1397    def test_trashcan_recursion(self):
1398        # See bpo-33930
1399
1400        def foo():
1401            o = object()
1402            for x in range(1_000_000):
1403                # Create a big chain of method objects that will trigger
1404                # a deep chain of calls when they need to be destructed.
1405                o = o.__dir__
1406
1407        foo()
1408        support.gc_collect()
1409
1410    @cpython_only
1411    def test_recursion_normalizing_exception(self):
1412        import_module("_testinternalcapi")
1413        # Issue #22898.
1414        # Test that a RecursionError is raised when tstate->recursion_depth is
1415        # equal to recursion_limit in PyErr_NormalizeException() and check
1416        # that a ResourceWarning is printed.
1417        # Prior to #22898, the recursivity of PyErr_NormalizeException() was
1418        # controlled by tstate->recursion_depth and a PyExc_RecursionErrorInst
1419        # singleton was being used in that case, that held traceback data and
1420        # locals indefinitely and would cause a segfault in _PyExc_Fini() upon
1421        # finalization of these locals.
1422        code = """if 1:
1423            import sys
1424            from _testinternalcapi import get_recursion_depth
1425            from test import support
1426
1427            class MyException(Exception): pass
1428
1429            def setrecursionlimit(depth):
1430                while 1:
1431                    try:
1432                        sys.setrecursionlimit(depth)
1433                        return depth
1434                    except RecursionError:
1435                        # sys.setrecursionlimit() raises a RecursionError if
1436                        # the new recursion limit is too low (issue #25274).
1437                        depth += 1
1438
1439            def recurse(cnt):
1440                cnt -= 1
1441                if cnt:
1442                    recurse(cnt)
1443                else:
1444                    generator.throw(MyException)
1445
1446            def gen():
1447                f = open(%a, mode='rb', buffering=0)
1448                yield
1449
1450            generator = gen()
1451            next(generator)
1452            recursionlimit = sys.getrecursionlimit()
1453            try:
1454                recurse(support.exceeds_recursion_limit())
1455            finally:
1456                sys.setrecursionlimit(recursionlimit)
1457                print('Done.')
1458        """ % __file__
1459        rc, out, err = script_helper.assert_python_failure("-Wd", "-c", code)
1460        # Check that the program does not fail with SIGABRT.
1461        self.assertEqual(rc, 1)
1462        self.assertIn(b'RecursionError', err)
1463        self.assertIn(b'ResourceWarning', err)
1464        self.assertIn(b'Done.', out)
1465
1466    @cpython_only
1467    @unittest.skipIf(_testcapi is None, "requires _testcapi")
1468    def test_recursion_normalizing_infinite_exception(self):
1469        # Issue #30697. Test that a RecursionError is raised when
1470        # maximum recursion depth has been exceeded when creating
1471        # an exception
1472        code = """if 1:
1473            import _testcapi
1474            try:
1475                raise _testcapi.RecursingInfinitelyError
1476            finally:
1477                print('Done.')
1478        """
1479        rc, out, err = script_helper.assert_python_failure("-c", code)
1480        self.assertEqual(rc, 1)
1481        expected = b'RecursionError: maximum recursion depth exceeded'
1482        self.assertTrue(expected in err, msg=f"{expected!r} not found in {err[:3_000]!r}... (truncated)")
1483        self.assertIn(b'Done.', out)
1484
1485
1486    def test_recursion_in_except_handler(self):
1487
1488        def set_relative_recursion_limit(n):
1489            depth = 1
1490            while True:
1491                try:
1492                    sys.setrecursionlimit(depth)
1493                except RecursionError:
1494                    depth += 1
1495                else:
1496                    break
1497            sys.setrecursionlimit(depth+n)
1498
1499        def recurse_in_except():
1500            try:
1501                1/0
1502            except:
1503                recurse_in_except()
1504
1505        def recurse_after_except():
1506            try:
1507                1/0
1508            except:
1509                pass
1510            recurse_after_except()
1511
1512        def recurse_in_body_and_except():
1513            try:
1514                recurse_in_body_and_except()
1515            except:
1516                recurse_in_body_and_except()
1517
1518        recursionlimit = sys.getrecursionlimit()
1519        try:
1520            set_relative_recursion_limit(10)
1521            for func in (recurse_in_except, recurse_after_except, recurse_in_body_and_except):
1522                with self.subTest(func=func):
1523                    try:
1524                        func()
1525                    except RecursionError:
1526                        pass
1527                    else:
1528                        self.fail("Should have raised a RecursionError")
1529        finally:
1530            sys.setrecursionlimit(recursionlimit)
1531
1532
1533    @cpython_only
1534    # Python built with Py_TRACE_REFS fail with a fatal error in
1535    # _PyRefchain_Trace() on memory allocation error.
1536    @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build')
1537    @unittest.skipIf(_testcapi is None, "requires _testcapi")
1538    def test_recursion_normalizing_with_no_memory(self):
1539        # Issue #30697. Test that in the abort that occurs when there is no
1540        # memory left and the size of the Python frames stack is greater than
1541        # the size of the list of preallocated MemoryError instances, the
1542        # Fatal Python error message mentions MemoryError.
1543        code = """if 1:
1544            import _testcapi
1545            class C(): pass
1546            def recurse(cnt):
1547                cnt -= 1
1548                if cnt:
1549                    recurse(cnt)
1550                else:
1551                    _testcapi.set_nomemory(0)
1552                    C()
1553            recurse(16)
1554        """
1555        with SuppressCrashReport():
1556            rc, out, err = script_helper.assert_python_failure("-c", code)
1557            self.assertIn(b'MemoryError', err)
1558
1559    @cpython_only
1560    @unittest.skipIf(_testcapi is None, "requires _testcapi")
1561    def test_MemoryError(self):
1562        # PyErr_NoMemory always raises the same exception instance.
1563        # Check that the traceback is not doubled.
1564        import traceback
1565        from _testcapi import raise_memoryerror
1566        def raiseMemError():
1567            try:
1568                raise_memoryerror()
1569            except MemoryError as e:
1570                tb = e.__traceback__
1571            else:
1572                self.fail("Should have raised a MemoryError")
1573            return traceback.format_tb(tb)
1574
1575        tb1 = raiseMemError()
1576        tb2 = raiseMemError()
1577        self.assertEqual(tb1, tb2)
1578
1579    @cpython_only
1580    @unittest.skipIf(_testcapi is None, "requires _testcapi")
1581    def test_exception_with_doc(self):
1582        doc2 = "This is a test docstring."
1583        doc4 = "This is another test docstring."
1584
1585        self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
1586                          "error1")
1587
1588        # test basic usage of PyErr_NewException
1589        error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
1590        self.assertIs(type(error1), type)
1591        self.assertTrue(issubclass(error1, Exception))
1592        self.assertIsNone(error1.__doc__)
1593
1594        # test with given docstring
1595        error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
1596        self.assertEqual(error2.__doc__, doc2)
1597
1598        # test with explicit base (without docstring)
1599        error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
1600                                                   base=error2)
1601        self.assertTrue(issubclass(error3, error2))
1602
1603        # test with explicit base tuple
1604        class C(object):
1605            pass
1606        error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
1607                                                   (error3, C))
1608        self.assertTrue(issubclass(error4, error3))
1609        self.assertTrue(issubclass(error4, C))
1610        self.assertEqual(error4.__doc__, doc4)
1611
1612        # test with explicit dictionary
1613        error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
1614                                                   error4, {'a': 1})
1615        self.assertTrue(issubclass(error5, error4))
1616        self.assertEqual(error5.a, 1)
1617        self.assertEqual(error5.__doc__, "")
1618
1619    @cpython_only
1620    @unittest.skipIf(_testcapi is None, "requires _testcapi")
1621    def test_memory_error_cleanup(self):
1622        # Issue #5437: preallocated MemoryError instances should not keep
1623        # traceback objects alive.
1624        from _testcapi import raise_memoryerror
1625        class C:
1626            pass
1627        wr = None
1628        def inner():
1629            nonlocal wr
1630            c = C()
1631            wr = weakref.ref(c)
1632            raise_memoryerror()
1633        # We cannot use assertRaises since it manually deletes the traceback
1634        try:
1635            inner()
1636        except MemoryError as e:
1637            self.assertNotEqual(wr(), None)
1638        else:
1639            self.fail("MemoryError not raised")
1640        gc_collect()  # For PyPy or other GCs.
1641        self.assertEqual(wr(), None)
1642
1643    @no_tracing
1644    def test_recursion_error_cleanup(self):
1645        # Same test as above, but with "recursion exceeded" errors
1646        class C:
1647            pass
1648        wr = None
1649        def inner():
1650            nonlocal wr
1651            c = C()
1652            wr = weakref.ref(c)
1653            inner()
1654        # We cannot use assertRaises since it manually deletes the traceback
1655        try:
1656            inner()
1657        except RecursionError as e:
1658            self.assertNotEqual(wr(), None)
1659        else:
1660            self.fail("RecursionError not raised")
1661        gc_collect()  # For PyPy or other GCs.
1662        self.assertEqual(wr(), None)
1663
1664    def test_errno_ENOTDIR(self):
1665        # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
1666        with self.assertRaises(OSError) as cm:
1667            os.listdir(__file__)
1668        self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception)
1669
1670    def test_unraisable(self):
1671        # Issue #22836: PyErr_WriteUnraisable() should give sensible reports
1672        class BrokenDel:
1673            def __del__(self):
1674                exc = ValueError("del is broken")
1675                # The following line is included in the traceback report:
1676                raise exc
1677
1678        obj = BrokenDel()
1679        with support.catch_unraisable_exception() as cm:
1680            del obj
1681
1682            gc_collect()  # For PyPy or other GCs.
1683            self.assertEqual(cm.unraisable.object, BrokenDel.__del__)
1684            self.assertIsNotNone(cm.unraisable.exc_traceback)
1685
1686    def test_unhandled(self):
1687        # Check for sensible reporting of unhandled exceptions
1688        for exc_type in (ValueError, BrokenStrException):
1689            with self.subTest(exc_type):
1690                try:
1691                    exc = exc_type("test message")
1692                    # The following line is included in the traceback report:
1693                    raise exc
1694                except exc_type:
1695                    with captured_stderr() as stderr:
1696                        sys.__excepthook__(*sys.exc_info())
1697                report = stderr.getvalue()
1698                self.assertIn("test_exceptions.py", report)
1699                self.assertIn("raise exc", report)
1700                self.assertIn(exc_type.__name__, report)
1701                if exc_type is BrokenStrException:
1702                    self.assertIn("<exception str() failed>", report)
1703                else:
1704                    self.assertIn("test message", report)
1705                self.assertTrue(report.endswith("\n"))
1706
1707    @cpython_only
1708    # Python built with Py_TRACE_REFS fail with a fatal error in
1709    # _PyRefchain_Trace() on memory allocation error.
1710    @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build')
1711    @unittest.skipIf(_testcapi is None, "requires _testcapi")
1712    def test_memory_error_in_PyErr_PrintEx(self):
1713        code = """if 1:
1714            import _testcapi
1715            class C(): pass
1716            _testcapi.set_nomemory(0, %d)
1717            C()
1718        """
1719
1720        # Issue #30817: Abort in PyErr_PrintEx() when no memory.
1721        # Span a large range of tests as the CPython code always evolves with
1722        # changes that add or remove memory allocations.
1723        for i in range(1, 20):
1724            rc, out, err = script_helper.assert_python_failure("-c", code % i)
1725            self.assertIn(rc, (1, 120))
1726            self.assertIn(b'MemoryError', err)
1727
1728    def test_yield_in_nested_try_excepts(self):
1729        #Issue #25612
1730        class MainError(Exception):
1731            pass
1732
1733        class SubError(Exception):
1734            pass
1735
1736        def main():
1737            try:
1738                raise MainError()
1739            except MainError:
1740                try:
1741                    yield
1742                except SubError:
1743                    pass
1744                raise
1745
1746        coro = main()
1747        coro.send(None)
1748        with self.assertRaises(MainError):
1749            coro.throw(SubError())
1750
1751    def test_generator_doesnt_retain_old_exc2(self):
1752        #Issue 28884#msg282532
1753        def g():
1754            try:
1755                raise ValueError
1756            except ValueError:
1757                yield 1
1758            self.assertIsNone(sys.exception())
1759            yield 2
1760
1761        gen = g()
1762
1763        try:
1764            raise IndexError
1765        except IndexError:
1766            self.assertEqual(next(gen), 1)
1767        self.assertEqual(next(gen), 2)
1768
1769    def test_raise_in_generator(self):
1770        #Issue 25612#msg304117
1771        def g():
1772            yield 1
1773            raise
1774            yield 2
1775
1776        with self.assertRaises(ZeroDivisionError):
1777            i = g()
1778            try:
1779                1/0
1780            except:
1781                next(i)
1782                next(i)
1783
1784    @unittest.skipUnless(__debug__, "Won't work if __debug__ is False")
1785    def test_assert_shadowing(self):
1786        # Shadowing AssertionError would cause the assert statement to
1787        # misbehave.
1788        global AssertionError
1789        AssertionError = TypeError
1790        try:
1791            assert False, 'hello'
1792        except BaseException as e:
1793            del AssertionError
1794            self.assertIsInstance(e, AssertionError)
1795            self.assertEqual(str(e), 'hello')
1796        else:
1797            del AssertionError
1798            self.fail('Expected exception')
1799
1800    def test_memory_error_subclasses(self):
1801        # bpo-41654: MemoryError instances use a freelist of objects that are
1802        # linked using the 'dict' attribute when they are inactive/dead.
1803        # Subclasses of MemoryError should not participate in the freelist
1804        # schema. This test creates a MemoryError object and keeps it alive
1805        # (therefore advancing the freelist) and then it creates and destroys a
1806        # subclass object. Finally, it checks that creating a new MemoryError
1807        # succeeds, proving that the freelist is not corrupted.
1808
1809        class TestException(MemoryError):
1810            pass
1811
1812        try:
1813            raise MemoryError
1814        except MemoryError as exc:
1815            inst = exc
1816
1817        try:
1818            raise TestException
1819        except Exception:
1820            pass
1821
1822        for _ in range(10):
1823            try:
1824                raise MemoryError
1825            except MemoryError as exc:
1826                pass
1827
1828            gc_collect()
1829
1830    @unittest.skipIf(_testcapi is None, "requires _testcapi")
1831    def test_memory_error_in_subinterp(self):
1832        # gh-109894: subinterpreters shouldn't count on last resort memory error
1833        # when MemoryError is raised through PyErr_NoMemory() call,
1834        # and should preallocate memory errors as does the main interpreter.
1835        # interp.static_objects.last_resort_memory_error.args
1836        # should be initialized to empty tuple to avoid crash on attempt to print it.
1837        code = f"""if 1:
1838            import _testcapi
1839            _testcapi.run_in_subinterp(\"[0]*{sys.maxsize}\")
1840            exit(0)
1841        """
1842        rc, _, err = script_helper.assert_python_ok("-c", code)
1843        self.assertIn(b'MemoryError', err)
1844
1845
1846class NameErrorTests(unittest.TestCase):
1847    def test_name_error_has_name(self):
1848        try:
1849            bluch
1850        except NameError as exc:
1851            self.assertEqual("bluch", exc.name)
1852
1853    def test_issue45826(self):
1854        # regression test for bpo-45826
1855        def f():
1856            with self.assertRaisesRegex(NameError, 'aaa'):
1857                aab
1858
1859        try:
1860            f()
1861        except self.failureException:
1862            with support.captured_stderr() as err:
1863                sys.__excepthook__(*sys.exc_info())
1864        else:
1865            self.fail("assertRaisesRegex should have failed.")
1866
1867        self.assertIn("aab", err.getvalue())
1868
1869    def test_issue45826_focused(self):
1870        def f():
1871            try:
1872                nonsense
1873            except BaseException as E:
1874                E.with_traceback(None)
1875                raise ZeroDivisionError()
1876
1877        try:
1878            f()
1879        except ZeroDivisionError:
1880            with support.captured_stderr() as err:
1881                sys.__excepthook__(*sys.exc_info())
1882
1883        self.assertIn("nonsense", err.getvalue())
1884        self.assertIn("ZeroDivisionError", err.getvalue())
1885
1886    def test_gh_111654(self):
1887        def f():
1888            class TestClass:
1889                TestClass
1890
1891        self.assertRaises(NameError, f)
1892
1893    # Note: name suggestion tests live in `test_traceback`.
1894
1895
1896class AttributeErrorTests(unittest.TestCase):
1897    def test_attributes(self):
1898        # Setting 'attr' should not be a problem.
1899        exc = AttributeError('Ouch!')
1900        self.assertIsNone(exc.name)
1901        self.assertIsNone(exc.obj)
1902
1903        sentinel = object()
1904        exc = AttributeError('Ouch', name='carry', obj=sentinel)
1905        self.assertEqual(exc.name, 'carry')
1906        self.assertIs(exc.obj, sentinel)
1907
1908    def test_getattr_has_name_and_obj(self):
1909        class A:
1910            blech = None
1911
1912        obj = A()
1913        try:
1914            obj.bluch
1915        except AttributeError as exc:
1916            self.assertEqual("bluch", exc.name)
1917            self.assertEqual(obj, exc.obj)
1918        try:
1919            object.__getattribute__(obj, "bluch")
1920        except AttributeError as exc:
1921            self.assertEqual("bluch", exc.name)
1922            self.assertEqual(obj, exc.obj)
1923
1924    def test_getattr_has_name_and_obj_for_method(self):
1925        class A:
1926            def blech(self):
1927                return
1928
1929        obj = A()
1930        try:
1931            obj.bluch()
1932        except AttributeError as exc:
1933            self.assertEqual("bluch", exc.name)
1934            self.assertEqual(obj, exc.obj)
1935
1936    # Note: name suggestion tests live in `test_traceback`.
1937
1938
1939class ImportErrorTests(unittest.TestCase):
1940
1941    def test_attributes(self):
1942        # Setting 'name' and 'path' should not be a problem.
1943        exc = ImportError('test')
1944        self.assertIsNone(exc.name)
1945        self.assertIsNone(exc.path)
1946
1947        exc = ImportError('test', name='somemodule')
1948        self.assertEqual(exc.name, 'somemodule')
1949        self.assertIsNone(exc.path)
1950
1951        exc = ImportError('test', path='somepath')
1952        self.assertEqual(exc.path, 'somepath')
1953        self.assertIsNone(exc.name)
1954
1955        exc = ImportError('test', path='somepath', name='somename')
1956        self.assertEqual(exc.name, 'somename')
1957        self.assertEqual(exc.path, 'somepath')
1958
1959        msg = r"ImportError\(\) got an unexpected keyword argument 'invalid'"
1960        with self.assertRaisesRegex(TypeError, msg):
1961            ImportError('test', invalid='keyword')
1962
1963        with self.assertRaisesRegex(TypeError, msg):
1964            ImportError('test', name='name', invalid='keyword')
1965
1966        with self.assertRaisesRegex(TypeError, msg):
1967            ImportError('test', path='path', invalid='keyword')
1968
1969        with self.assertRaisesRegex(TypeError, msg):
1970            ImportError(invalid='keyword')
1971
1972        with self.assertRaisesRegex(TypeError, msg):
1973            ImportError('test', invalid='keyword', another=True)
1974
1975    def test_reset_attributes(self):
1976        exc = ImportError('test', name='name', path='path')
1977        self.assertEqual(exc.args, ('test',))
1978        self.assertEqual(exc.msg, 'test')
1979        self.assertEqual(exc.name, 'name')
1980        self.assertEqual(exc.path, 'path')
1981
1982        # Reset not specified attributes
1983        exc.__init__()
1984        self.assertEqual(exc.args, ())
1985        self.assertEqual(exc.msg, None)
1986        self.assertEqual(exc.name, None)
1987        self.assertEqual(exc.path, None)
1988
1989    def test_non_str_argument(self):
1990        # Issue #15778
1991        with check_warnings(('', BytesWarning), quiet=True):
1992            arg = b'abc'
1993            exc = ImportError(arg)
1994            self.assertEqual(str(arg), str(exc))
1995
1996    def test_copy_pickle(self):
1997        for kwargs in (dict(),
1998                       dict(name='somename'),
1999                       dict(path='somepath'),
2000                       dict(name='somename', path='somepath')):
2001            orig = ImportError('test', **kwargs)
2002            for proto in range(pickle.HIGHEST_PROTOCOL + 1):
2003                exc = pickle.loads(pickle.dumps(orig, proto))
2004                self.assertEqual(exc.args, ('test',))
2005                self.assertEqual(exc.msg, 'test')
2006                self.assertEqual(exc.name, orig.name)
2007                self.assertEqual(exc.path, orig.path)
2008            for c in copy.copy, copy.deepcopy:
2009                exc = c(orig)
2010                self.assertEqual(exc.args, ('test',))
2011                self.assertEqual(exc.msg, 'test')
2012                self.assertEqual(exc.name, orig.name)
2013                self.assertEqual(exc.path, orig.path)
2014
2015
2016def run_script(source):
2017    if isinstance(source, str):
2018        with open(TESTFN, 'w', encoding='utf-8') as testfile:
2019            testfile.write(dedent(source))
2020    else:
2021        with open(TESTFN, 'wb') as testfile:
2022            testfile.write(source)
2023    _rc, _out, err = script_helper.assert_python_failure('-Wd', '-X', 'utf8', TESTFN)
2024    return err.decode('utf-8').splitlines()
2025
2026class AssertionErrorTests(unittest.TestCase):
2027    def tearDown(self):
2028        unlink(TESTFN)
2029
2030    @force_not_colorized
2031    def test_assertion_error_location(self):
2032        cases = [
2033            ('assert None',
2034                [
2035                    '    assert None',
2036                    '           ^^^^',
2037                    'AssertionError',
2038                ],
2039            ),
2040            ('assert 0',
2041                [
2042                    '    assert 0',
2043                    '           ^',
2044                    'AssertionError',
2045                ],
2046            ),
2047            ('assert 1 > 2',
2048                [
2049                    '    assert 1 > 2',
2050                    '           ^^^^^',
2051                    'AssertionError',
2052                ],
2053            ),
2054            ('assert 1 > 2 and 3 > 2',
2055                [
2056                    '    assert 1 > 2 and 3 > 2',
2057                    '           ^^^^^^^^^^^^^^^',
2058                    'AssertionError',
2059                ],
2060            ),
2061            ('assert 1 > 2, "messäge"',
2062                [
2063                    '    assert 1 > 2, "messäge"',
2064                    '           ^^^^^',
2065                    'AssertionError: messäge',
2066                ],
2067            ),
2068            ('assert 1 > 2, "messäge"'.encode(),
2069                [
2070                    '    assert 1 > 2, "messäge"',
2071                    '           ^^^^^',
2072                    'AssertionError: messäge',
2073                ],
2074            ),
2075            ('# coding: latin1\nassert 1 > 2, "messäge"'.encode('latin1'),
2076                [
2077                    '    assert 1 > 2, "messäge"',
2078                    '           ^^^^^',
2079                    'AssertionError: messäge',
2080                ],
2081            ),
2082            (BOM_UTF8 + 'assert 1 > 2, "messäge"'.encode(),
2083                [
2084                    '    assert 1 > 2, "messäge"',
2085                    '           ^^^^^',
2086                    'AssertionError: messäge',
2087                ],
2088            ),
2089
2090            # Multiline:
2091            ("""
2092             assert (
2093                 1 > 2)
2094             """,
2095                [
2096                    '    1 > 2)',
2097                    '    ^^^^^',
2098                    'AssertionError',
2099                ],
2100            ),
2101            ("""
2102             assert (
2103                 1 > 2), "Message"
2104             """,
2105                [
2106                    '    1 > 2), "Message"',
2107                    '    ^^^^^',
2108                    'AssertionError: Message',
2109                ],
2110            ),
2111            ("""
2112             assert (
2113                 1 > 2), \\
2114                 "Message"
2115             """,
2116                [
2117                    '    1 > 2), \\',
2118                    '    ^^^^^',
2119                    'AssertionError: Message',
2120                ],
2121            ),
2122        ]
2123        for source, expected in cases:
2124            with self.subTest(source=source):
2125                result = run_script(source)
2126                self.assertEqual(result[-3:], expected)
2127
2128    @force_not_colorized
2129    def test_multiline_not_highlighted(self):
2130        cases = [
2131            ("""
2132             assert (
2133                 1 > 2
2134             )
2135             """,
2136                [
2137                    '    1 > 2',
2138                    'AssertionError',
2139                ],
2140            ),
2141            ("""
2142             assert (
2143                 1 < 2 and
2144                 3 > 4
2145             )
2146             """,
2147                [
2148                    '    1 < 2 and',
2149                    '    3 > 4',
2150                    'AssertionError',
2151                ],
2152            ),
2153        ]
2154        for source, expected in cases:
2155            with self.subTest(source=source):
2156                result = run_script(source)
2157                self.assertEqual(result[-len(expected):], expected)
2158
2159
2160class SyntaxErrorTests(unittest.TestCase):
2161    maxDiff = None
2162
2163    @force_not_colorized
2164    def test_range_of_offsets(self):
2165        cases = [
2166            # Basic range from 2->7
2167            (("bad.py", 1, 2, "abcdefg", 1, 7),
2168             dedent(
2169             """
2170               File "bad.py", line 1
2171                 abcdefg
2172                  ^^^^^
2173             SyntaxError: bad bad
2174             """)),
2175            # end_offset = start_offset + 1
2176            (("bad.py", 1, 2, "abcdefg", 1, 3),
2177             dedent(
2178             """
2179               File "bad.py", line 1
2180                 abcdefg
2181                  ^
2182             SyntaxError: bad bad
2183             """)),
2184            # Negative end offset
2185            (("bad.py", 1, 2, "abcdefg", 1, -2),
2186             dedent(
2187             """
2188               File "bad.py", line 1
2189                 abcdefg
2190                  ^
2191             SyntaxError: bad bad
2192             """)),
2193            # end offset before starting offset
2194            (("bad.py", 1, 4, "abcdefg", 1, 2),
2195             dedent(
2196             """
2197               File "bad.py", line 1
2198                 abcdefg
2199                    ^
2200             SyntaxError: bad bad
2201             """)),
2202            # Both offsets negative
2203            (("bad.py", 1, -4, "abcdefg", 1, -2),
2204             dedent(
2205             """
2206               File "bad.py", line 1
2207                 abcdefg
2208             SyntaxError: bad bad
2209             """)),
2210            # Both offsets negative and the end more negative
2211            (("bad.py", 1, -4, "abcdefg", 1, -5),
2212             dedent(
2213             """
2214               File "bad.py", line 1
2215                 abcdefg
2216             SyntaxError: bad bad
2217             """)),
2218            # Both offsets 0
2219            (("bad.py", 1, 0, "abcdefg", 1, 0),
2220             dedent(
2221             """
2222               File "bad.py", line 1
2223                 abcdefg
2224             SyntaxError: bad bad
2225             """)),
2226            # Start offset 0 and end offset not 0
2227            (("bad.py", 1, 0, "abcdefg", 1, 5),
2228             dedent(
2229             """
2230               File "bad.py", line 1
2231                 abcdefg
2232             SyntaxError: bad bad
2233             """)),
2234            # End offset pass the source length
2235            (("bad.py", 1, 2, "abcdefg", 1, 100),
2236             dedent(
2237             """
2238               File "bad.py", line 1
2239                 abcdefg
2240                  ^^^^^^
2241             SyntaxError: bad bad
2242             """)),
2243        ]
2244        for args, expected in cases:
2245            with self.subTest(args=args):
2246                try:
2247                    raise SyntaxError("bad bad", args)
2248                except SyntaxError as exc:
2249                    with support.captured_stderr() as err:
2250                        sys.__excepthook__(*sys.exc_info())
2251                    self.assertIn(expected, err.getvalue())
2252                    the_exception = exc
2253
2254    def test_encodings(self):
2255        self.addCleanup(unlink, TESTFN)
2256        source = (
2257            '# -*- coding: cp437 -*-\n'
2258            '"¢¢¢¢¢¢" + f(4, x for x in range(1))\n'
2259        )
2260        err = run_script(source.encode('cp437'))
2261        self.assertEqual(err[-3], '    "¢¢¢¢¢¢" + f(4, x for x in range(1))')
2262        self.assertEqual(err[-2], '                          ^^^^^^^^^^^^^^^^^^^')
2263
2264        # Check backwards tokenizer errors
2265        source = '# -*- coding: ascii -*-\n\n(\n'
2266        err = run_script(source)
2267        self.assertEqual(err[-3], '    (')
2268        self.assertEqual(err[-2], '    ^')
2269
2270    def test_non_utf8(self):
2271        # Check non utf-8 characters
2272        self.addCleanup(unlink, TESTFN)
2273        err = run_script(b"\x89")
2274        self.assertIn("SyntaxError: Non-UTF-8 code starting with '\\x89' in file", err[-1])
2275
2276    def test_string_source(self):
2277        def try_compile(source):
2278            with self.assertRaises(SyntaxError) as cm:
2279                compile(source, '<string>', 'exec')
2280            return cm.exception
2281
2282        exc = try_compile('return "ä"')
2283        self.assertEqual(str(exc), "'return' outside function (<string>, line 1)")
2284        self.assertIsNone(exc.text)
2285        self.assertEqual(exc.offset, 1)
2286        self.assertEqual(exc.end_offset, 12)
2287
2288        exc = try_compile('return "ä"'.encode())
2289        self.assertEqual(str(exc), "'return' outside function (<string>, line 1)")
2290        self.assertIsNone(exc.text)
2291        self.assertEqual(exc.offset, 1)
2292        self.assertEqual(exc.end_offset, 12)
2293
2294        exc = try_compile(BOM_UTF8 + 'return "ä"'.encode())
2295        self.assertEqual(str(exc), "'return' outside function (<string>, line 1)")
2296        self.assertIsNone(exc.text)
2297        self.assertEqual(exc.offset, 1)
2298        self.assertEqual(exc.end_offset, 12)
2299
2300        exc = try_compile('# coding: latin1\nreturn "ä"'.encode('latin1'))
2301        self.assertEqual(str(exc), "'return' outside function (<string>, line 2)")
2302        self.assertIsNone(exc.text)
2303        self.assertEqual(exc.offset, 1)
2304        self.assertEqual(exc.end_offset, 12)
2305
2306        exc = try_compile('return "ä" #' + 'ä'*1000)
2307        self.assertEqual(str(exc), "'return' outside function (<string>, line 1)")
2308        self.assertIsNone(exc.text)
2309        self.assertEqual(exc.offset, 1)
2310        self.assertEqual(exc.end_offset, 12)
2311
2312        exc = try_compile('return "ä" # ' + 'ä'*1000)
2313        self.assertEqual(str(exc), "'return' outside function (<string>, line 1)")
2314        self.assertIsNone(exc.text)
2315        self.assertEqual(exc.offset, 1)
2316        self.assertEqual(exc.end_offset, 12)
2317
2318    def test_file_source(self):
2319        self.addCleanup(unlink, TESTFN)
2320        err = run_script('return "ä"')
2321        self.assertEqual(err[-3:], [
2322                         '    return "ä"',
2323                         '    ^^^^^^^^^^',
2324                         "SyntaxError: 'return' outside function"])
2325
2326        err = run_script('return "ä"'.encode())
2327        self.assertEqual(err[-3:], [
2328                         '    return "ä"',
2329                         '    ^^^^^^^^^^',
2330                         "SyntaxError: 'return' outside function"])
2331
2332        err = run_script(BOM_UTF8 + 'return "ä"'.encode())
2333        self.assertEqual(err[-3:], [
2334                         '    return "ä"',
2335                         '    ^^^^^^^^^^',
2336                         "SyntaxError: 'return' outside function"])
2337
2338        err = run_script('# coding: latin1\nreturn "ä"'.encode('latin1'))
2339        self.assertEqual(err[-3:], [
2340                         '    return "ä"',
2341                         '    ^^^^^^^^^^',
2342                         "SyntaxError: 'return' outside function"])
2343
2344        err = run_script('return "ä" #' + 'ä'*1000)
2345        self.assertEqual(err[-2:], [
2346                         '    ^^^^^^^^^^^',
2347                         "SyntaxError: 'return' outside function"])
2348        self.assertEqual(err[-3][:100], '    return "ä" #' + 'ä'*84)
2349
2350        err = run_script('return "ä" # ' + 'ä'*1000)
2351        self.assertEqual(err[-2:], [
2352                         '    ^^^^^^^^^^^',
2353                         "SyntaxError: 'return' outside function"])
2354        self.assertEqual(err[-3][:100], '    return "ä" # ' + 'ä'*83)
2355
2356    def test_attributes_new_constructor(self):
2357        args = ("bad.py", 1, 2, "abcdefg", 1, 100)
2358        the_exception = SyntaxError("bad bad", args)
2359        filename, lineno, offset, error, end_lineno, end_offset = args
2360        self.assertEqual(filename, the_exception.filename)
2361        self.assertEqual(lineno, the_exception.lineno)
2362        self.assertEqual(end_lineno, the_exception.end_lineno)
2363        self.assertEqual(offset, the_exception.offset)
2364        self.assertEqual(end_offset, the_exception.end_offset)
2365        self.assertEqual(error, the_exception.text)
2366        self.assertEqual("bad bad", the_exception.msg)
2367
2368    def test_attributes_old_constructor(self):
2369        args = ("bad.py", 1, 2, "abcdefg")
2370        the_exception = SyntaxError("bad bad", args)
2371        filename, lineno, offset, error = args
2372        self.assertEqual(filename, the_exception.filename)
2373        self.assertEqual(lineno, the_exception.lineno)
2374        self.assertEqual(None, the_exception.end_lineno)
2375        self.assertEqual(offset, the_exception.offset)
2376        self.assertEqual(None, the_exception.end_offset)
2377        self.assertEqual(error, the_exception.text)
2378        self.assertEqual("bad bad", the_exception.msg)
2379
2380    def test_incorrect_constructor(self):
2381        args = ("bad.py", 1, 2)
2382        self.assertRaises(TypeError, SyntaxError, "bad bad", args)
2383
2384        args = ("bad.py", 1, 2, 4, 5, 6, 7)
2385        self.assertRaises(TypeError, SyntaxError, "bad bad", args)
2386
2387        args = ("bad.py", 1, 2, "abcdefg", 1)
2388        self.assertRaises(TypeError, SyntaxError, "bad bad", args)
2389
2390
2391class TestInvalidExceptionMatcher(unittest.TestCase):
2392    def test_except_star_invalid_exception_type(self):
2393        with self.assertRaises(TypeError):
2394            try:
2395                raise ValueError
2396            except 42:
2397                pass
2398
2399        with self.assertRaises(TypeError):
2400            try:
2401                raise ValueError
2402            except (ValueError, 42):
2403                pass
2404
2405
2406class PEP626Tests(unittest.TestCase):
2407
2408    def lineno_after_raise(self, f, *expected):
2409        try:
2410            f()
2411        except Exception as ex:
2412            t = ex.__traceback__
2413        else:
2414            self.fail("No exception raised")
2415        lines = []
2416        t = t.tb_next # Skip this function
2417        while t:
2418            frame = t.tb_frame
2419            lines.append(
2420                None if frame.f_lineno is None else
2421                frame.f_lineno-frame.f_code.co_firstlineno
2422            )
2423            t = t.tb_next
2424        self.assertEqual(tuple(lines), expected)
2425
2426    def test_lineno_after_raise_simple(self):
2427        def simple():
2428            1/0
2429            pass
2430        self.lineno_after_raise(simple, 1)
2431
2432    def test_lineno_after_raise_in_except(self):
2433        def in_except():
2434            try:
2435                1/0
2436            except:
2437                1/0
2438                pass
2439        self.lineno_after_raise(in_except, 4)
2440
2441    def test_lineno_after_other_except(self):
2442        def other_except():
2443            try:
2444                1/0
2445            except TypeError as ex:
2446                pass
2447        self.lineno_after_raise(other_except, 3)
2448
2449    def test_lineno_in_named_except(self):
2450        def in_named_except():
2451            try:
2452                1/0
2453            except Exception as ex:
2454                1/0
2455                pass
2456        self.lineno_after_raise(in_named_except, 4)
2457
2458    def test_lineno_in_try(self):
2459        def in_try():
2460            try:
2461                1/0
2462            finally:
2463                pass
2464        self.lineno_after_raise(in_try, 4)
2465
2466    def test_lineno_in_finally_normal(self):
2467        def in_finally_normal():
2468            try:
2469                pass
2470            finally:
2471                1/0
2472                pass
2473        self.lineno_after_raise(in_finally_normal, 4)
2474
2475    def test_lineno_in_finally_except(self):
2476        def in_finally_except():
2477            try:
2478                1/0
2479            finally:
2480                1/0
2481                pass
2482        self.lineno_after_raise(in_finally_except, 4)
2483
2484    def test_lineno_after_with(self):
2485        class Noop:
2486            def __enter__(self):
2487                return self
2488            def __exit__(self, *args):
2489                pass
2490        def after_with():
2491            with Noop():
2492                1/0
2493                pass
2494        self.lineno_after_raise(after_with, 2)
2495
2496    def test_missing_lineno_shows_as_none(self):
2497        def f():
2498            1/0
2499        self.lineno_after_raise(f, 1)
2500        f.__code__ = f.__code__.replace(co_linetable=b'\xf8\xf8\xf8\xf9\xf8\xf8\xf8')
2501        self.lineno_after_raise(f, None)
2502
2503    def test_lineno_after_raise_in_with_exit(self):
2504        class ExitFails:
2505            def __enter__(self):
2506                return self
2507            def __exit__(self, *args):
2508                raise ValueError
2509
2510        def after_with():
2511            with ExitFails():
2512                1/0
2513        self.lineno_after_raise(after_with, 1, 1)
2514
2515if __name__ == '__main__':
2516    unittest.main()
2517