python (3.12.0)
1 import errno
2 import os
3 import re
4 import sys
5 import unittest
6
7 from test import support
8 from test.support import import_helper
9 from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE
10 from test.support.script_helper import assert_python_failure
11 from test.support.testcase import ExceptionIsLikeMixin
12
13 from .test_misc import decode_stderr
14
15 # Skip this test if the _testcapi module isn't available.
16 _testcapi = import_helper.import_module('_testcapi')
17
18 NULL = None
19
20 class ESC[4;38;5;81mTest_Exceptions(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
21
22 def test_exception(self):
23 raised_exception = ValueError("5")
24 new_exc = TypeError("TEST")
25 try:
26 raise raised_exception
27 except ValueError as e:
28 orig_sys_exception = sys.exception()
29 orig_exception = _testcapi.set_exception(new_exc)
30 new_sys_exception = sys.exception()
31 new_exception = _testcapi.set_exception(orig_exception)
32 reset_sys_exception = sys.exception()
33
34 self.assertEqual(orig_exception, e)
35
36 self.assertEqual(orig_exception, raised_exception)
37 self.assertEqual(orig_sys_exception, orig_exception)
38 self.assertEqual(reset_sys_exception, orig_exception)
39 self.assertEqual(new_exception, new_exc)
40 self.assertEqual(new_sys_exception, new_exception)
41 else:
42 self.fail("Exception not raised")
43
44 def test_exc_info(self):
45 raised_exception = ValueError("5")
46 new_exc = TypeError("TEST")
47 try:
48 raise raised_exception
49 except ValueError as e:
50 tb = e.__traceback__
51 orig_sys_exc_info = sys.exc_info()
52 orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None)
53 new_sys_exc_info = sys.exc_info()
54 new_exc_info = _testcapi.set_exc_info(*orig_exc_info)
55 reset_sys_exc_info = sys.exc_info()
56
57 self.assertEqual(orig_exc_info[1], e)
58
59 self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb))
60 self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info)
61 self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info)
62 self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None))
63 self.assertSequenceEqual(new_sys_exc_info, new_exc_info)
64 else:
65 self.assertTrue(False)
66
67
68 class ESC[4;38;5;81mTest_FatalError(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
69
70 def check_fatal_error(self, code, expected, not_expected=()):
71 with support.SuppressCrashReport():
72 rc, out, err = assert_python_failure('-sSI', '-c', code)
73
74 err = decode_stderr(err)
75 self.assertIn('Fatal Python error: _testcapi_fatal_error_impl: MESSAGE\n',
76 err)
77
78 match = re.search(r'^Extension modules:(.*) \(total: ([0-9]+)\)$',
79 err, re.MULTILINE)
80 if not match:
81 self.fail(f"Cannot find 'Extension modules:' in {err!r}")
82 modules = set(match.group(1).strip().split(', '))
83 total = int(match.group(2))
84
85 for name in expected:
86 self.assertIn(name, modules)
87 for name in not_expected:
88 self.assertNotIn(name, modules)
89 self.assertEqual(len(modules), total)
90
91 @support.requires_subprocess()
92 def test_fatal_error(self):
93 # By default, stdlib extension modules are ignored,
94 # but not test modules.
95 expected = ('_testcapi',)
96 not_expected = ('sys',)
97 code = 'import _testcapi, sys; _testcapi.fatal_error(b"MESSAGE")'
98 self.check_fatal_error(code, expected, not_expected)
99
100 # Mark _testcapi as stdlib module, but not sys
101 expected = ('sys',)
102 not_expected = ('_testcapi',)
103 code = """if True:
104 import _testcapi, sys
105 sys.stdlib_module_names = frozenset({"_testcapi"})
106 _testcapi.fatal_error(b"MESSAGE")
107 """
108 self.check_fatal_error(code, expected)
109
110
111 class ESC[4;38;5;81mTest_ErrSetAndRestore(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
112
113 def test_err_set_raised(self):
114 with self.assertRaises(ValueError):
115 _testcapi.err_set_raised(ValueError())
116 v = ValueError()
117 try:
118 _testcapi.err_set_raised(v)
119 except ValueError as ex:
120 self.assertIs(v, ex)
121
122 def test_err_restore(self):
123 with self.assertRaises(ValueError):
124 _testcapi.err_restore(ValueError)
125 with self.assertRaises(ValueError):
126 _testcapi.err_restore(ValueError, 1)
127 with self.assertRaises(ValueError):
128 _testcapi.err_restore(ValueError, 1, None)
129 with self.assertRaises(ValueError):
130 _testcapi.err_restore(ValueError, ValueError())
131 try:
132 _testcapi.err_restore(KeyError, "hi")
133 except KeyError as k:
134 self.assertEqual("hi", k.args[0])
135 try:
136 1/0
137 except Exception as e:
138 tb = e.__traceback__
139 with self.assertRaises(ValueError):
140 _testcapi.err_restore(ValueError, 1, tb)
141 with self.assertRaises(TypeError):
142 _testcapi.err_restore(ValueError, 1, 0)
143 try:
144 _testcapi.err_restore(ValueError, 1, tb)
145 except ValueError as v:
146 self.assertEqual(1, v.args[0])
147 self.assertIs(tb, v.__traceback__.tb_next)
148
149 def test_set_object(self):
150
151 # new exception as obj is not an exception
152 with self.assertRaises(ValueError) as e:
153 _testcapi.exc_set_object(ValueError, 42)
154 self.assertEqual(e.exception.args, (42,))
155
156 # wraps the exception because unrelated types
157 with self.assertRaises(ValueError) as e:
158 _testcapi.exc_set_object(ValueError, TypeError(1,2,3))
159 wrapped = e.exception.args[0]
160 self.assertIsInstance(wrapped, TypeError)
161 self.assertEqual(wrapped.args, (1, 2, 3))
162
163 # is superclass, so does not wrap
164 with self.assertRaises(PermissionError) as e:
165 _testcapi.exc_set_object(OSError, PermissionError(24))
166 self.assertEqual(e.exception.args, (24,))
167
168 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
169 def __subclasscheck__(cls, sub):
170 1/0
171
172 class ESC[4;38;5;81mBroken(ESC[4;38;5;149mException, metaclass=ESC[4;38;5;149mMeta):
173 pass
174
175 with self.assertRaises(ZeroDivisionError) as e:
176 _testcapi.exc_set_object(Broken, Broken())
177
178 def test_set_object_and_fetch(self):
179 class ESC[4;38;5;81mBroken(ESC[4;38;5;149mException):
180 def __init__(self, *arg):
181 raise ValueError("Broken __init__")
182
183 exc = _testcapi.exc_set_object_fetch(Broken, 'abcd')
184 self.assertIsInstance(exc, ValueError)
185 self.assertEqual(exc.__notes__[0],
186 "Normalization failed: type=Broken args='abcd'")
187
188 class ESC[4;38;5;81mBadArg:
189 def __repr__(self):
190 raise TypeError('Broken arg type')
191
192 exc = _testcapi.exc_set_object_fetch(Broken, BadArg())
193 self.assertIsInstance(exc, ValueError)
194 self.assertEqual(exc.__notes__[0],
195 'Normalization failed: type=Broken args=<unknown>')
196
197 def test_set_string(self):
198 """Test PyErr_SetString()"""
199 setstring = _testcapi.err_setstring
200 with self.assertRaises(ZeroDivisionError) as e:
201 setstring(ZeroDivisionError, b'error')
202 self.assertEqual(e.exception.args, ('error',))
203 with self.assertRaises(ZeroDivisionError) as e:
204 setstring(ZeroDivisionError, 'помилка'.encode())
205 self.assertEqual(e.exception.args, ('помилка',))
206
207 with self.assertRaises(UnicodeDecodeError):
208 setstring(ZeroDivisionError, b'\xff')
209 self.assertRaises(SystemError, setstring, list, b'error')
210 # CRASHES setstring(ZeroDivisionError, NULL)
211 # CRASHES setstring(NULL, b'error')
212
213 def test_format(self):
214 """Test PyErr_Format()"""
215 import_helper.import_module('ctypes')
216 from ctypes import pythonapi, py_object, c_char_p, c_int
217 name = "PyErr_Format"
218 PyErr_Format = getattr(pythonapi, name)
219 PyErr_Format.argtypes = (py_object, c_char_p,)
220 PyErr_Format.restype = py_object
221 with self.assertRaises(ZeroDivisionError) as e:
222 PyErr_Format(ZeroDivisionError, b'%s %d', b'error', c_int(42))
223 self.assertEqual(e.exception.args, ('error 42',))
224 with self.assertRaises(ZeroDivisionError) as e:
225 PyErr_Format(ZeroDivisionError, b'%s', 'помилка'.encode())
226 self.assertEqual(e.exception.args, ('помилка',))
227
228 with self.assertRaisesRegex(OverflowError, 'not in range'):
229 PyErr_Format(ZeroDivisionError, b'%c', c_int(-1))
230 with self.assertRaisesRegex(ValueError, 'format string'):
231 PyErr_Format(ZeroDivisionError, b'\xff')
232 self.assertRaises(SystemError, PyErr_Format, list, b'error')
233 # CRASHES PyErr_Format(ZeroDivisionError, NULL)
234 # CRASHES PyErr_Format(py_object(), b'error')
235
236 def test_setfromerrnowithfilename(self):
237 """Test PyErr_SetFromErrnoWithFilename()"""
238 setfromerrnowithfilename = _testcapi.err_setfromerrnowithfilename
239 ENOENT = errno.ENOENT
240 with self.assertRaises(FileNotFoundError) as e:
241 setfromerrnowithfilename(ENOENT, OSError, b'file')
242 self.assertEqual(e.exception.args,
243 (ENOENT, 'No such file or directory'))
244 self.assertEqual(e.exception.errno, ENOENT)
245 self.assertEqual(e.exception.filename, 'file')
246
247 with self.assertRaises(FileNotFoundError) as e:
248 setfromerrnowithfilename(ENOENT, OSError, os.fsencode(TESTFN))
249 self.assertEqual(e.exception.filename, TESTFN)
250
251 if TESTFN_UNDECODABLE:
252 with self.assertRaises(FileNotFoundError) as e:
253 setfromerrnowithfilename(ENOENT, OSError, TESTFN_UNDECODABLE)
254 self.assertEqual(e.exception.filename,
255 os.fsdecode(TESTFN_UNDECODABLE))
256
257 with self.assertRaises(FileNotFoundError) as e:
258 setfromerrnowithfilename(ENOENT, OSError, NULL)
259 self.assertIsNone(e.exception.filename)
260
261 with self.assertRaises(OSError) as e:
262 setfromerrnowithfilename(0, OSError, b'file')
263 self.assertEqual(e.exception.args, (0, 'Error'))
264 self.assertEqual(e.exception.errno, 0)
265 self.assertEqual(e.exception.filename, 'file')
266
267 with self.assertRaises(ZeroDivisionError) as e:
268 setfromerrnowithfilename(ENOENT, ZeroDivisionError, b'file')
269 self.assertEqual(e.exception.args,
270 (ENOENT, 'No such file or directory', 'file'))
271 # CRASHES setfromerrnowithfilename(ENOENT, NULL, b'error')
272
273
274 class ESC[4;38;5;81mTest_PyUnstable_Exc_PrepReraiseStar(ESC[4;38;5;149mExceptionIsLikeMixin, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
275
276 def setUp(self):
277 super().setUp()
278 try:
279 raise ExceptionGroup("eg", [TypeError('bad type'), ValueError(42)])
280 except ExceptionGroup as e:
281 self.orig = e
282
283 def test_invalid_args(self):
284 with self.assertRaisesRegex(TypeError, "orig must be an exception"):
285 _testcapi.unstable_exc_prep_reraise_star(42, [None])
286
287 with self.assertRaisesRegex(TypeError, "excs must be a list"):
288 _testcapi.unstable_exc_prep_reraise_star(self.orig, 42)
289
290 with self.assertRaisesRegex(TypeError, "not an exception"):
291 _testcapi.unstable_exc_prep_reraise_star(self.orig, [TypeError(42), 42])
292
293 with self.assertRaisesRegex(ValueError, "orig must be a raised exception"):
294 _testcapi.unstable_exc_prep_reraise_star(ValueError(42), [TypeError(42)])
295
296 with self.assertRaisesRegex(ValueError, "orig must be a raised exception"):
297 _testcapi.unstable_exc_prep_reraise_star(ExceptionGroup("eg", [ValueError(42)]),
298 [TypeError(42)])
299
300
301 def test_nothing_to_reraise(self):
302 self.assertEqual(
303 _testcapi.unstable_exc_prep_reraise_star(self.orig, [None]), None)
304
305 try:
306 raise ValueError(42)
307 except ValueError as e:
308 orig = e
309 self.assertEqual(
310 _testcapi.unstable_exc_prep_reraise_star(orig, [None]), None)
311
312 def test_reraise_orig(self):
313 orig = self.orig
314 res = _testcapi.unstable_exc_prep_reraise_star(orig, [orig])
315 self.assertExceptionIsLike(res, orig)
316
317 def test_raise_orig_parts(self):
318 orig = self.orig
319 match, rest = orig.split(TypeError)
320
321 test_cases = [
322 ([match, rest], orig),
323 ([rest, match], orig),
324 ([match], match),
325 ([rest], rest),
326 ([], None),
327 ]
328
329 for input, expected in test_cases:
330 with self.subTest(input=input):
331 res = _testcapi.unstable_exc_prep_reraise_star(orig, input)
332 self.assertExceptionIsLike(res, expected)
333
334
335 def test_raise_with_new_exceptions(self):
336 orig = self.orig
337
338 match, rest = orig.split(TypeError)
339 new1 = OSError('bad file')
340 new2 = RuntimeError('bad runtime')
341
342 test_cases = [
343 ([new1, match, rest], ExceptionGroup("", [new1, orig])),
344 ([match, new1, rest], ExceptionGroup("", [new1, orig])),
345 ([match, rest, new1], ExceptionGroup("", [new1, orig])),
346
347 ([new1, new2, match, rest], ExceptionGroup("", [new1, new2, orig])),
348 ([new1, match, new2, rest], ExceptionGroup("", [new1, new2, orig])),
349 ([new2, rest, match, new1], ExceptionGroup("", [new2, new1, orig])),
350 ([rest, new2, match, new1], ExceptionGroup("", [new2, new1, orig])),
351
352
353 ([new1, new2, rest], ExceptionGroup("", [new1, new2, rest])),
354 ([new1, match, new2], ExceptionGroup("", [new1, new2, match])),
355 ([rest, new2, new1], ExceptionGroup("", [new2, new1, rest])),
356 ([new1, new2], ExceptionGroup("", [new1, new2])),
357 ([new2, new1], ExceptionGroup("", [new2, new1])),
358 ]
359
360 for (input, expected) in test_cases:
361 with self.subTest(input=input):
362 res = _testcapi.unstable_exc_prep_reraise_star(orig, input)
363 self.assertExceptionIsLike(res, expected)
364
365
366 if __name__ == "__main__":
367 unittest.main()