| 
									
										
										
										
											2023-08-19 14:51:03 +03:00
										 |  |  | import errno | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2023-02-23 16:03:13 +01:00
										 |  |  | import re | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import unittest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from test import support | 
					
						
							|  |  |  | from test.support import import_helper | 
					
						
							| 
									
										
										
										
											2023-08-19 14:51:03 +03:00
										 |  |  | from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE | 
					
						
							| 
									
										
										
										
											2023-02-23 16:03:13 +01:00
										 |  |  | from test.support.script_helper import assert_python_failure | 
					
						
							| 
									
										
										
										
											2023-05-30 15:03:36 +01:00
										 |  |  | from test.support.testcase import ExceptionIsLikeMixin | 
					
						
							| 
									
										
										
										
											2023-02-23 16:03:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | from .test_misc import decode_stderr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Skip this test if the _testcapi module isn't available. | 
					
						
							|  |  |  | _testcapi = import_helper.import_module('_testcapi') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-19 14:51:03 +03:00
										 |  |  | NULL = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 19:01:03 +02:00
										 |  |  | class CustomError(Exception): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-23 16:03:13 +01:00
										 |  |  | class Test_Exceptions(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_exception(self): | 
					
						
							|  |  |  |         raised_exception = ValueError("5") | 
					
						
							|  |  |  |         new_exc = TypeError("TEST") | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             raise raised_exception | 
					
						
							|  |  |  |         except ValueError as e: | 
					
						
							|  |  |  |             orig_sys_exception = sys.exception() | 
					
						
							|  |  |  |             orig_exception = _testcapi.set_exception(new_exc) | 
					
						
							|  |  |  |             new_sys_exception = sys.exception() | 
					
						
							|  |  |  |             new_exception = _testcapi.set_exception(orig_exception) | 
					
						
							|  |  |  |             reset_sys_exception = sys.exception() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.assertEqual(orig_exception, e) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.assertEqual(orig_exception, raised_exception) | 
					
						
							|  |  |  |             self.assertEqual(orig_sys_exception, orig_exception) | 
					
						
							|  |  |  |             self.assertEqual(reset_sys_exception, orig_exception) | 
					
						
							|  |  |  |             self.assertEqual(new_exception, new_exc) | 
					
						
							|  |  |  |             self.assertEqual(new_sys_exception, new_exception) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.fail("Exception not raised") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_exc_info(self): | 
					
						
							|  |  |  |         raised_exception = ValueError("5") | 
					
						
							|  |  |  |         new_exc = TypeError("TEST") | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             raise raised_exception | 
					
						
							|  |  |  |         except ValueError as e: | 
					
						
							|  |  |  |             tb = e.__traceback__ | 
					
						
							|  |  |  |             orig_sys_exc_info = sys.exc_info() | 
					
						
							|  |  |  |             orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None) | 
					
						
							|  |  |  |             new_sys_exc_info = sys.exc_info() | 
					
						
							|  |  |  |             new_exc_info = _testcapi.set_exc_info(*orig_exc_info) | 
					
						
							|  |  |  |             reset_sys_exc_info = sys.exc_info() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.assertEqual(orig_exc_info[1], e) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb)) | 
					
						
							|  |  |  |             self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info) | 
					
						
							|  |  |  |             self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info) | 
					
						
							|  |  |  |             self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None)) | 
					
						
							|  |  |  |             self.assertSequenceEqual(new_sys_exc_info, new_exc_info) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.assertTrue(False) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Test_FatalError(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_fatal_error(self, code, expected, not_expected=()): | 
					
						
							|  |  |  |         with support.SuppressCrashReport(): | 
					
						
							|  |  |  |             rc, out, err = assert_python_failure('-sSI', '-c', code) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = decode_stderr(err) | 
					
						
							| 
									
										
										
										
											2023-05-21 18:39:45 +09:00
										 |  |  |         self.assertIn('Fatal Python error: _testcapi_fatal_error_impl: MESSAGE\n', | 
					
						
							| 
									
										
										
										
											2023-02-23 16:03:13 +01:00
										 |  |  |                       err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         match = re.search(r'^Extension modules:(.*) \(total: ([0-9]+)\)$', | 
					
						
							|  |  |  |                           err, re.MULTILINE) | 
					
						
							|  |  |  |         if not match: | 
					
						
							|  |  |  |             self.fail(f"Cannot find 'Extension modules:' in {err!r}") | 
					
						
							|  |  |  |         modules = set(match.group(1).strip().split(', ')) | 
					
						
							|  |  |  |         total = int(match.group(2)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for name in expected: | 
					
						
							|  |  |  |             self.assertIn(name, modules) | 
					
						
							|  |  |  |         for name in not_expected: | 
					
						
							|  |  |  |             self.assertNotIn(name, modules) | 
					
						
							|  |  |  |         self.assertEqual(len(modules), total) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @support.requires_subprocess() | 
					
						
							|  |  |  |     def test_fatal_error(self): | 
					
						
							|  |  |  |         # By default, stdlib extension modules are ignored, | 
					
						
							|  |  |  |         # but not test modules. | 
					
						
							|  |  |  |         expected = ('_testcapi',) | 
					
						
							|  |  |  |         not_expected = ('sys',) | 
					
						
							|  |  |  |         code = 'import _testcapi, sys; _testcapi.fatal_error(b"MESSAGE")' | 
					
						
							|  |  |  |         self.check_fatal_error(code, expected, not_expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Mark _testcapi as stdlib module, but not sys | 
					
						
							|  |  |  |         expected = ('sys',) | 
					
						
							|  |  |  |         not_expected = ('_testcapi',) | 
					
						
							|  |  |  |         code = """if True:
 | 
					
						
							|  |  |  |             import _testcapi, sys | 
					
						
							|  |  |  |             sys.stdlib_module_names = frozenset({"_testcapi"}) | 
					
						
							|  |  |  |             _testcapi.fatal_error(b"MESSAGE") | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.check_fatal_error(code, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Test_ErrSetAndRestore(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_err_set_raised(self): | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             _testcapi.err_set_raised(ValueError()) | 
					
						
							|  |  |  |         v = ValueError() | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             _testcapi.err_set_raised(v) | 
					
						
							|  |  |  |         except ValueError as ex: | 
					
						
							|  |  |  |             self.assertIs(v, ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_err_restore(self): | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             _testcapi.err_restore(ValueError) | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             _testcapi.err_restore(ValueError, 1) | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             _testcapi.err_restore(ValueError, 1, None) | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             _testcapi.err_restore(ValueError, ValueError()) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             _testcapi.err_restore(KeyError, "hi") | 
					
						
							|  |  |  |         except KeyError as k: | 
					
						
							|  |  |  |             self.assertEqual("hi", k.args[0]) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             1/0 | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             tb = e.__traceback__ | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							|  |  |  |             _testcapi.err_restore(ValueError, 1, tb) | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             _testcapi.err_restore(ValueError, 1, 0) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             _testcapi.err_restore(ValueError, 1, tb) | 
					
						
							|  |  |  |         except ValueError as v: | 
					
						
							|  |  |  |             self.assertEqual(1, v.args[0]) | 
					
						
							|  |  |  |             self.assertIs(tb, v.__traceback__.tb_next) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-07 21:27:46 +00:00
										 |  |  |     def test_set_object(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # new exception as obj is not an exception | 
					
						
							|  |  |  |         with self.assertRaises(ValueError) as e: | 
					
						
							|  |  |  |             _testcapi.exc_set_object(ValueError, 42) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, (42,)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # wraps the exception because unrelated types | 
					
						
							|  |  |  |         with self.assertRaises(ValueError) as e: | 
					
						
							|  |  |  |             _testcapi.exc_set_object(ValueError, TypeError(1,2,3)) | 
					
						
							|  |  |  |         wrapped = e.exception.args[0] | 
					
						
							|  |  |  |         self.assertIsInstance(wrapped, TypeError) | 
					
						
							|  |  |  |         self.assertEqual(wrapped.args, (1, 2, 3)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # is superclass, so does not wrap | 
					
						
							|  |  |  |         with self.assertRaises(PermissionError) as e: | 
					
						
							|  |  |  |             _testcapi.exc_set_object(OSError, PermissionError(24)) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, (24,)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Meta(type): | 
					
						
							|  |  |  |             def __subclasscheck__(cls, sub): | 
					
						
							|  |  |  |                 1/0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Broken(Exception, metaclass=Meta): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(ZeroDivisionError) as e: | 
					
						
							|  |  |  |             _testcapi.exc_set_object(Broken, Broken()) | 
					
						
							| 
									
										
										
										
											2023-02-23 16:03:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-16 10:16:01 +00:00
										 |  |  |     def test_set_object_and_fetch(self): | 
					
						
							|  |  |  |         class Broken(Exception): | 
					
						
							|  |  |  |             def __init__(self, *arg): | 
					
						
							|  |  |  |                 raise ValueError("Broken __init__") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         exc = _testcapi.exc_set_object_fetch(Broken, 'abcd') | 
					
						
							|  |  |  |         self.assertIsInstance(exc, ValueError) | 
					
						
							|  |  |  |         self.assertEqual(exc.__notes__[0], | 
					
						
							|  |  |  |                          "Normalization failed: type=Broken args='abcd'") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class BadArg: | 
					
						
							|  |  |  |             def __repr__(self): | 
					
						
							|  |  |  |                 raise TypeError('Broken arg type') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         exc = _testcapi.exc_set_object_fetch(Broken, BadArg()) | 
					
						
							|  |  |  |         self.assertIsInstance(exc, ValueError) | 
					
						
							|  |  |  |         self.assertEqual(exc.__notes__[0], | 
					
						
							|  |  |  |                          'Normalization failed: type=Broken args=<unknown>') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-19 14:51:03 +03:00
										 |  |  |     def test_set_string(self): | 
					
						
							|  |  |  |         """Test PyErr_SetString()""" | 
					
						
							|  |  |  |         setstring = _testcapi.err_setstring | 
					
						
							|  |  |  |         with self.assertRaises(ZeroDivisionError) as e: | 
					
						
							|  |  |  |             setstring(ZeroDivisionError, b'error') | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, ('error',)) | 
					
						
							|  |  |  |         with self.assertRaises(ZeroDivisionError) as e: | 
					
						
							|  |  |  |             setstring(ZeroDivisionError, 'помилка'.encode()) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, ('помилка',)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(UnicodeDecodeError): | 
					
						
							|  |  |  |             setstring(ZeroDivisionError, b'\xff') | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setstring, list, b'error') | 
					
						
							|  |  |  |         # CRASHES setstring(ZeroDivisionError, NULL) | 
					
						
							|  |  |  |         # CRASHES setstring(NULL, b'error') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_format(self): | 
					
						
							|  |  |  |         """Test PyErr_Format()""" | 
					
						
							|  |  |  |         import_helper.import_module('ctypes') | 
					
						
							|  |  |  |         from ctypes import pythonapi, py_object, c_char_p, c_int | 
					
						
							|  |  |  |         name = "PyErr_Format" | 
					
						
							|  |  |  |         PyErr_Format = getattr(pythonapi, name) | 
					
						
							|  |  |  |         PyErr_Format.argtypes = (py_object, c_char_p,) | 
					
						
							|  |  |  |         PyErr_Format.restype = py_object | 
					
						
							|  |  |  |         with self.assertRaises(ZeroDivisionError) as e: | 
					
						
							|  |  |  |             PyErr_Format(ZeroDivisionError, b'%s %d', b'error', c_int(42)) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, ('error 42',)) | 
					
						
							|  |  |  |         with self.assertRaises(ZeroDivisionError) as e: | 
					
						
							|  |  |  |             PyErr_Format(ZeroDivisionError, b'%s', 'помилка'.encode()) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, ('помилка',)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(OverflowError, 'not in range'): | 
					
						
							|  |  |  |             PyErr_Format(ZeroDivisionError, b'%c', c_int(-1)) | 
					
						
							|  |  |  |         with self.assertRaisesRegex(ValueError, 'format string'): | 
					
						
							|  |  |  |             PyErr_Format(ZeroDivisionError, b'\xff') | 
					
						
							|  |  |  |         self.assertRaises(SystemError, PyErr_Format, list, b'error') | 
					
						
							|  |  |  |         # CRASHES PyErr_Format(ZeroDivisionError, NULL) | 
					
						
							|  |  |  |         # CRASHES PyErr_Format(py_object(), b'error') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_setfromerrnowithfilename(self): | 
					
						
							|  |  |  |         """Test PyErr_SetFromErrnoWithFilename()""" | 
					
						
							|  |  |  |         setfromerrnowithfilename = _testcapi.err_setfromerrnowithfilename | 
					
						
							|  |  |  |         ENOENT = errno.ENOENT | 
					
						
							|  |  |  |         with self.assertRaises(FileNotFoundError) as e: | 
					
						
							|  |  |  |             setfromerrnowithfilename(ENOENT, OSError, b'file') | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, | 
					
						
							|  |  |  |                          (ENOENT, 'No such file or directory')) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.errno, ENOENT) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.filename, 'file') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(FileNotFoundError) as e: | 
					
						
							|  |  |  |             setfromerrnowithfilename(ENOENT, OSError, os.fsencode(TESTFN)) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.filename, TESTFN) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if TESTFN_UNDECODABLE: | 
					
						
							|  |  |  |             with self.assertRaises(FileNotFoundError) as e: | 
					
						
							|  |  |  |                 setfromerrnowithfilename(ENOENT, OSError, TESTFN_UNDECODABLE) | 
					
						
							|  |  |  |             self.assertEqual(e.exception.filename, | 
					
						
							|  |  |  |                              os.fsdecode(TESTFN_UNDECODABLE)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(FileNotFoundError) as e: | 
					
						
							|  |  |  |             setfromerrnowithfilename(ENOENT, OSError, NULL) | 
					
						
							|  |  |  |         self.assertIsNone(e.exception.filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(OSError) as e: | 
					
						
							|  |  |  |             setfromerrnowithfilename(0, OSError, b'file') | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, (0, 'Error')) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.errno, 0) | 
					
						
							|  |  |  |         self.assertEqual(e.exception.filename, 'file') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(ZeroDivisionError) as e: | 
					
						
							|  |  |  |             setfromerrnowithfilename(ENOENT, ZeroDivisionError, b'file') | 
					
						
							|  |  |  |         self.assertEqual(e.exception.args, | 
					
						
							|  |  |  |                          (ENOENT, 'No such file or directory', 'file')) | 
					
						
							|  |  |  |         # CRASHES setfromerrnowithfilename(ENOENT, NULL, b'error') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 19:01:03 +02:00
										 |  |  |     def test_err_writeunraisable(self): | 
					
						
							|  |  |  |         # Test PyErr_WriteUnraisable() | 
					
						
							|  |  |  |         writeunraisable = _testcapi.err_writeunraisable | 
					
						
							|  |  |  |         firstline = self.test_err_writeunraisable.__code__.co_firstlineno | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with support.catch_unraisable_exception() as cm: | 
					
						
							|  |  |  |             writeunraisable(CustomError('oops!'), hex) | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_type, CustomError) | 
					
						
							|  |  |  |             self.assertEqual(str(cm.unraisable.exc_value), 'oops!') | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, | 
					
						
							|  |  |  |                              firstline + 6) | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.err_msg) | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.object, hex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with support.catch_unraisable_exception() as cm: | 
					
						
							|  |  |  |             writeunraisable(CustomError('oops!'), NULL) | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_type, CustomError) | 
					
						
							|  |  |  |             self.assertEqual(str(cm.unraisable.exc_value), 'oops!') | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, | 
					
						
							|  |  |  |                              firstline + 15) | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.err_msg) | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.object) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with (support.swap_attr(sys, 'unraisablehook', None), | 
					
						
							|  |  |  |               support.captured_stderr() as stderr): | 
					
						
							|  |  |  |             writeunraisable(CustomError('oops!'), hex) | 
					
						
							|  |  |  |         lines = stderr.getvalue().splitlines() | 
					
						
							|  |  |  |         self.assertEqual(lines[0], f'Exception ignored in: {hex!r}') | 
					
						
							|  |  |  |         self.assertEqual(lines[1], 'Traceback (most recent call last):') | 
					
						
							|  |  |  |         self.assertEqual(lines[-1], f'{__name__}.CustomError: oops!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with (support.swap_attr(sys, 'unraisablehook', None), | 
					
						
							|  |  |  |               support.captured_stderr() as stderr): | 
					
						
							|  |  |  |             writeunraisable(CustomError('oops!'), NULL) | 
					
						
							|  |  |  |         lines = stderr.getvalue().splitlines() | 
					
						
							|  |  |  |         self.assertEqual(lines[0], 'Traceback (most recent call last):') | 
					
						
							|  |  |  |         self.assertEqual(lines[-1], f'{__name__}.CustomError: oops!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CRASHES writeunraisable(NULL, hex) | 
					
						
							|  |  |  |         # CRASHES writeunraisable(NULL, NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 23:42:44 +02:00
										 |  |  |     def test_err_formatunraisable(self): | 
					
						
							|  |  |  |         # Test PyErr_FormatUnraisable() | 
					
						
							|  |  |  |         formatunraisable = _testcapi.err_formatunraisable | 
					
						
							|  |  |  |         firstline = self.test_err_formatunraisable.__code__.co_firstlineno | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with support.catch_unraisable_exception() as cm: | 
					
						
							|  |  |  |             formatunraisable(CustomError('oops!'), b'Error in %R', []) | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_type, CustomError) | 
					
						
							|  |  |  |             self.assertEqual(str(cm.unraisable.exc_value), 'oops!') | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, | 
					
						
							|  |  |  |                              firstline + 6) | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.err_msg, 'Error in []') | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.object) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with support.catch_unraisable_exception() as cm: | 
					
						
							|  |  |  |             formatunraisable(CustomError('oops!'), b'undecodable \xff') | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_type, CustomError) | 
					
						
							|  |  |  |             self.assertEqual(str(cm.unraisable.exc_value), 'oops!') | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, | 
					
						
							|  |  |  |                              firstline + 15) | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.err_msg) | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.object) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with support.catch_unraisable_exception() as cm: | 
					
						
							|  |  |  |             formatunraisable(CustomError('oops!'), NULL) | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_type, CustomError) | 
					
						
							|  |  |  |             self.assertEqual(str(cm.unraisable.exc_value), 'oops!') | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, | 
					
						
							|  |  |  |                              firstline + 24) | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.err_msg) | 
					
						
							|  |  |  |             self.assertIsNone(cm.unraisable.object) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with (support.swap_attr(sys, 'unraisablehook', None), | 
					
						
							|  |  |  |               support.captured_stderr() as stderr): | 
					
						
							|  |  |  |             formatunraisable(CustomError('oops!'), b'Error in %R', []) | 
					
						
							|  |  |  |         lines = stderr.getvalue().splitlines() | 
					
						
							|  |  |  |         self.assertEqual(lines[0], f'Error in []:') | 
					
						
							|  |  |  |         self.assertEqual(lines[1], 'Traceback (most recent call last):') | 
					
						
							|  |  |  |         self.assertEqual(lines[-1], f'{__name__}.CustomError: oops!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with (support.swap_attr(sys, 'unraisablehook', None), | 
					
						
							|  |  |  |               support.captured_stderr() as stderr): | 
					
						
							|  |  |  |             formatunraisable(CustomError('oops!'), b'undecodable \xff') | 
					
						
							|  |  |  |         lines = stderr.getvalue().splitlines() | 
					
						
							|  |  |  |         self.assertEqual(lines[0], 'Traceback (most recent call last):') | 
					
						
							|  |  |  |         self.assertEqual(lines[-1], f'{__name__}.CustomError: oops!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with (support.swap_attr(sys, 'unraisablehook', None), | 
					
						
							|  |  |  |               support.captured_stderr() as stderr): | 
					
						
							|  |  |  |             formatunraisable(CustomError('oops!'), NULL) | 
					
						
							|  |  |  |         lines = stderr.getvalue().splitlines() | 
					
						
							|  |  |  |         self.assertEqual(lines[0], 'Traceback (most recent call last):') | 
					
						
							|  |  |  |         self.assertEqual(lines[-1], f'{__name__}.CustomError: oops!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CRASHES formatunraisable(NULL, b'Error in %R', []) | 
					
						
							|  |  |  |         # CRASHES formatunraisable(NULL, NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-16 10:16:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-30 15:03:36 +01:00
										 |  |  | class Test_PyUnstable_Exc_PrepReraiseStar(ExceptionIsLikeMixin, unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         super().setUp() | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             raise ExceptionGroup("eg", [TypeError('bad type'), ValueError(42)]) | 
					
						
							|  |  |  |         except ExceptionGroup as e: | 
					
						
							|  |  |  |             self.orig = e | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_invalid_args(self): | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, "orig must be an exception"): | 
					
						
							|  |  |  |             _testcapi.unstable_exc_prep_reraise_star(42, [None]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, "excs must be a list"): | 
					
						
							|  |  |  |             _testcapi.unstable_exc_prep_reraise_star(self.orig, 42) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, "not an exception"): | 
					
						
							|  |  |  |             _testcapi.unstable_exc_prep_reraise_star(self.orig, [TypeError(42), 42]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(ValueError, "orig must be a raised exception"): | 
					
						
							|  |  |  |             _testcapi.unstable_exc_prep_reraise_star(ValueError(42), [TypeError(42)]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(ValueError, "orig must be a raised exception"): | 
					
						
							|  |  |  |             _testcapi.unstable_exc_prep_reraise_star(ExceptionGroup("eg", [ValueError(42)]), | 
					
						
							|  |  |  |                                                      [TypeError(42)]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_nothing_to_reraise(self): | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testcapi.unstable_exc_prep_reraise_star(self.orig, [None]), None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             raise ValueError(42) | 
					
						
							|  |  |  |         except ValueError as e: | 
					
						
							|  |  |  |             orig = e | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testcapi.unstable_exc_prep_reraise_star(orig, [None]), None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_reraise_orig(self): | 
					
						
							|  |  |  |         orig = self.orig | 
					
						
							|  |  |  |         res = _testcapi.unstable_exc_prep_reraise_star(orig, [orig]) | 
					
						
							|  |  |  |         self.assertExceptionIsLike(res, orig) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_raise_orig_parts(self): | 
					
						
							|  |  |  |         orig = self.orig | 
					
						
							|  |  |  |         match, rest = orig.split(TypeError) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         test_cases = [ | 
					
						
							|  |  |  |             ([match, rest], orig), | 
					
						
							|  |  |  |             ([rest, match], orig), | 
					
						
							|  |  |  |             ([match], match), | 
					
						
							|  |  |  |             ([rest], rest), | 
					
						
							|  |  |  |             ([], None), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for input, expected in test_cases: | 
					
						
							|  |  |  |             with self.subTest(input=input): | 
					
						
							|  |  |  |                 res = _testcapi.unstable_exc_prep_reraise_star(orig, input) | 
					
						
							|  |  |  |                 self.assertExceptionIsLike(res, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_raise_with_new_exceptions(self): | 
					
						
							|  |  |  |         orig = self.orig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         match, rest = orig.split(TypeError) | 
					
						
							|  |  |  |         new1 = OSError('bad file') | 
					
						
							|  |  |  |         new2 = RuntimeError('bad runtime') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         test_cases = [ | 
					
						
							|  |  |  |             ([new1, match, rest], ExceptionGroup("", [new1, orig])), | 
					
						
							|  |  |  |             ([match, new1, rest], ExceptionGroup("", [new1, orig])), | 
					
						
							|  |  |  |             ([match, rest, new1], ExceptionGroup("", [new1, orig])), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ([new1, new2, match, rest], ExceptionGroup("", [new1, new2, orig])), | 
					
						
							|  |  |  |             ([new1, match, new2, rest], ExceptionGroup("", [new1, new2, orig])), | 
					
						
							|  |  |  |             ([new2, rest, match, new1], ExceptionGroup("", [new2, new1, orig])), | 
					
						
							|  |  |  |             ([rest, new2, match, new1], ExceptionGroup("", [new2, new1, orig])), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ([new1, new2, rest], ExceptionGroup("", [new1, new2, rest])), | 
					
						
							|  |  |  |             ([new1, match, new2], ExceptionGroup("", [new1, new2, match])), | 
					
						
							|  |  |  |             ([rest, new2, new1], ExceptionGroup("", [new2, new1, rest])), | 
					
						
							|  |  |  |             ([new1, new2], ExceptionGroup("", [new1, new2])), | 
					
						
							|  |  |  |             ([new2, new1], ExceptionGroup("", [new2, new1])), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (input, expected) in test_cases: | 
					
						
							|  |  |  |             with self.subTest(input=input): | 
					
						
							|  |  |  |                 res = _testcapi.unstable_exc_prep_reraise_star(orig, input) | 
					
						
							|  |  |  |                 self.assertExceptionIsLike(res, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-23 16:03:13 +01:00
										 |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     unittest.main() |