Skip to content

Commit 2131bed

Browse files
erlend-aaslandJelleZijlstra
authored andcommitted
pythongh-93649: Split exception tests from _testcapimodule.c (pythonGH-102173)
Automerge-Triggered-By: GH:erlend-aasland
1 parent 19b5e22 commit 2131bed

File tree

8 files changed

+434
-416
lines changed

8 files changed

+434
-416
lines changed

Lib/test/test_capi/test_exceptions.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import re
2+
import sys
3+
import unittest
4+
5+
from test import support
6+
from test.support import import_helper
7+
from test.support.script_helper import assert_python_failure
8+
9+
from .test_misc import decode_stderr
10+
11+
# Skip this test if the _testcapi module isn't available.
12+
_testcapi = import_helper.import_module('_testcapi')
13+
14+
class Test_Exceptions(unittest.TestCase):
15+
16+
def test_exception(self):
17+
raised_exception = ValueError("5")
18+
new_exc = TypeError("TEST")
19+
try:
20+
raise raised_exception
21+
except ValueError as e:
22+
orig_sys_exception = sys.exception()
23+
orig_exception = _testcapi.set_exception(new_exc)
24+
new_sys_exception = sys.exception()
25+
new_exception = _testcapi.set_exception(orig_exception)
26+
reset_sys_exception = sys.exception()
27+
28+
self.assertEqual(orig_exception, e)
29+
30+
self.assertEqual(orig_exception, raised_exception)
31+
self.assertEqual(orig_sys_exception, orig_exception)
32+
self.assertEqual(reset_sys_exception, orig_exception)
33+
self.assertEqual(new_exception, new_exc)
34+
self.assertEqual(new_sys_exception, new_exception)
35+
else:
36+
self.fail("Exception not raised")
37+
38+
def test_exc_info(self):
39+
raised_exception = ValueError("5")
40+
new_exc = TypeError("TEST")
41+
try:
42+
raise raised_exception
43+
except ValueError as e:
44+
tb = e.__traceback__
45+
orig_sys_exc_info = sys.exc_info()
46+
orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None)
47+
new_sys_exc_info = sys.exc_info()
48+
new_exc_info = _testcapi.set_exc_info(*orig_exc_info)
49+
reset_sys_exc_info = sys.exc_info()
50+
51+
self.assertEqual(orig_exc_info[1], e)
52+
53+
self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb))
54+
self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info)
55+
self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info)
56+
self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None))
57+
self.assertSequenceEqual(new_sys_exc_info, new_exc_info)
58+
else:
59+
self.assertTrue(False)
60+
61+
62+
class Test_FatalError(unittest.TestCase):
63+
64+
def check_fatal_error(self, code, expected, not_expected=()):
65+
with support.SuppressCrashReport():
66+
rc, out, err = assert_python_failure('-sSI', '-c', code)
67+
68+
err = decode_stderr(err)
69+
self.assertIn('Fatal Python error: test_fatal_error: MESSAGE\n',
70+
err)
71+
72+
match = re.search(r'^Extension modules:(.*) \(total: ([0-9]+)\)$',
73+
err, re.MULTILINE)
74+
if not match:
75+
self.fail(f"Cannot find 'Extension modules:' in {err!r}")
76+
modules = set(match.group(1).strip().split(', '))
77+
total = int(match.group(2))
78+
79+
for name in expected:
80+
self.assertIn(name, modules)
81+
for name in not_expected:
82+
self.assertNotIn(name, modules)
83+
self.assertEqual(len(modules), total)
84+
85+
@support.requires_subprocess()
86+
def test_fatal_error(self):
87+
# By default, stdlib extension modules are ignored,
88+
# but not test modules.
89+
expected = ('_testcapi',)
90+
not_expected = ('sys',)
91+
code = 'import _testcapi, sys; _testcapi.fatal_error(b"MESSAGE")'
92+
self.check_fatal_error(code, expected, not_expected)
93+
94+
# Mark _testcapi as stdlib module, but not sys
95+
expected = ('sys',)
96+
not_expected = ('_testcapi',)
97+
code = """if True:
98+
import _testcapi, sys
99+
sys.stdlib_module_names = frozenset({"_testcapi"})
100+
_testcapi.fatal_error(b"MESSAGE")
101+
"""
102+
self.check_fatal_error(code, expected)
103+
104+
105+
class Test_ErrSetAndRestore(unittest.TestCase):
106+
107+
def test_err_set_raised(self):
108+
with self.assertRaises(ValueError):
109+
_testcapi.err_set_raised(ValueError())
110+
v = ValueError()
111+
try:
112+
_testcapi.err_set_raised(v)
113+
except ValueError as ex:
114+
self.assertIs(v, ex)
115+
116+
def test_err_restore(self):
117+
with self.assertRaises(ValueError):
118+
_testcapi.err_restore(ValueError)
119+
with self.assertRaises(ValueError):
120+
_testcapi.err_restore(ValueError, 1)
121+
with self.assertRaises(ValueError):
122+
_testcapi.err_restore(ValueError, 1, None)
123+
with self.assertRaises(ValueError):
124+
_testcapi.err_restore(ValueError, ValueError())
125+
try:
126+
_testcapi.err_restore(KeyError, "hi")
127+
except KeyError as k:
128+
self.assertEqual("hi", k.args[0])
129+
try:
130+
1/0
131+
except Exception as e:
132+
tb = e.__traceback__
133+
with self.assertRaises(ValueError):
134+
_testcapi.err_restore(ValueError, 1, tb)
135+
with self.assertRaises(TypeError):
136+
_testcapi.err_restore(ValueError, 1, 0)
137+
try:
138+
_testcapi.err_restore(ValueError, 1, tb)
139+
except ValueError as v:
140+
self.assertEqual(1, v.args[0])
141+
self.assertIs(tb, v.__traceback__.tb_next)
142+
143+
144+
if __name__ == "__main__":
145+
unittest.main()

Lib/test/test_capi/test_misc.py

Lines changed: 3 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import os
99
import pickle
1010
import random
11-
import re
1211
import subprocess
1312
import sys
1413
import textwrap
@@ -91,51 +90,6 @@ def test_no_FatalError_infinite_loop(self):
9190
def test_memoryview_from_NULL_pointer(self):
9291
self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer)
9392

94-
def test_exception(self):
95-
raised_exception = ValueError("5")
96-
new_exc = TypeError("TEST")
97-
try:
98-
raise raised_exception
99-
except ValueError as e:
100-
orig_sys_exception = sys.exception()
101-
orig_exception = _testcapi.set_exception(new_exc)
102-
new_sys_exception = sys.exception()
103-
new_exception = _testcapi.set_exception(orig_exception)
104-
reset_sys_exception = sys.exception()
105-
106-
self.assertEqual(orig_exception, e)
107-
108-
self.assertEqual(orig_exception, raised_exception)
109-
self.assertEqual(orig_sys_exception, orig_exception)
110-
self.assertEqual(reset_sys_exception, orig_exception)
111-
self.assertEqual(new_exception, new_exc)
112-
self.assertEqual(new_sys_exception, new_exception)
113-
else:
114-
self.fail("Exception not raised")
115-
116-
def test_exc_info(self):
117-
raised_exception = ValueError("5")
118-
new_exc = TypeError("TEST")
119-
try:
120-
raise raised_exception
121-
except ValueError as e:
122-
tb = e.__traceback__
123-
orig_sys_exc_info = sys.exc_info()
124-
orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None)
125-
new_sys_exc_info = sys.exc_info()
126-
new_exc_info = _testcapi.set_exc_info(*orig_exc_info)
127-
reset_sys_exc_info = sys.exc_info()
128-
129-
self.assertEqual(orig_exc_info[1], e)
130-
131-
self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb))
132-
self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info)
133-
self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info)
134-
self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None))
135-
self.assertSequenceEqual(new_sys_exc_info, new_exc_info)
136-
else:
137-
self.assertTrue(False)
138-
13993
@unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.')
14094
def test_seq_bytes_to_charp_array(self):
14195
# Issue #15732: crash in _PySequence_BytesToCharpArray()
@@ -837,46 +791,6 @@ def __index__(self):
837791
self.assertRaises(TypeError, pynumber_tobase, '123', 10)
838792
self.assertRaises(SystemError, pynumber_tobase, 123, 0)
839793

840-
def check_fatal_error(self, code, expected, not_expected=()):
841-
with support.SuppressCrashReport():
842-
rc, out, err = assert_python_failure('-sSI', '-c', code)
843-
844-
err = decode_stderr(err)
845-
self.assertIn('Fatal Python error: test_fatal_error: MESSAGE\n',
846-
err)
847-
848-
match = re.search(r'^Extension modules:(.*) \(total: ([0-9]+)\)$',
849-
err, re.MULTILINE)
850-
if not match:
851-
self.fail(f"Cannot find 'Extension modules:' in {err!r}")
852-
modules = set(match.group(1).strip().split(', '))
853-
total = int(match.group(2))
854-
855-
for name in expected:
856-
self.assertIn(name, modules)
857-
for name in not_expected:
858-
self.assertNotIn(name, modules)
859-
self.assertEqual(len(modules), total)
860-
861-
@support.requires_subprocess()
862-
def test_fatal_error(self):
863-
# By default, stdlib extension modules are ignored,
864-
# but not test modules.
865-
expected = ('_testcapi',)
866-
not_expected = ('sys',)
867-
code = 'import _testcapi, sys; _testcapi.fatal_error(b"MESSAGE")'
868-
self.check_fatal_error(code, expected, not_expected)
869-
870-
# Mark _testcapi as stdlib module, but not sys
871-
expected = ('sys',)
872-
not_expected = ('_testcapi',)
873-
code = textwrap.dedent('''
874-
import _testcapi, sys
875-
sys.stdlib_module_names = frozenset({"_testcapi"})
876-
_testcapi.fatal_error(b"MESSAGE")
877-
''')
878-
self.check_fatal_error(code, expected)
879-
880794
def test_pyobject_repr_from_null(self):
881795
s = _testcapi.pyobject_repr_from_null()
882796
self.assertEqual(s, '<NULL>')
@@ -1214,9 +1128,9 @@ def test_pendingcalls_non_threaded(self):
12141128
self.pendingcalls_wait(l, n)
12151129

12161130
def test_gen_get_code(self):
1217-
def genf(): yield
1218-
gen = genf()
1219-
self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code)
1131+
def genf(): yield
1132+
gen = genf()
1133+
self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code)
12201134

12211135

12221136
class SubinterpreterTest(unittest.TestCase):
@@ -1641,44 +1555,5 @@ def func2(x=None):
16411555
self.do_test(func2)
16421556

16431557

1644-
class Test_ErrSetAndRestore(unittest.TestCase):
1645-
1646-
def test_err_set_raised(self):
1647-
with self.assertRaises(ValueError):
1648-
_testcapi.err_set_raised(ValueError())
1649-
v = ValueError()
1650-
try:
1651-
_testcapi.err_set_raised(v)
1652-
except ValueError as ex:
1653-
self.assertIs(v, ex)
1654-
1655-
def test_err_restore(self):
1656-
with self.assertRaises(ValueError):
1657-
_testcapi.err_restore(ValueError)
1658-
with self.assertRaises(ValueError):
1659-
_testcapi.err_restore(ValueError, 1)
1660-
with self.assertRaises(ValueError):
1661-
_testcapi.err_restore(ValueError, 1, None)
1662-
with self.assertRaises(ValueError):
1663-
_testcapi.err_restore(ValueError, ValueError())
1664-
try:
1665-
_testcapi.err_restore(KeyError, "hi")
1666-
except KeyError as k:
1667-
self.assertEqual("hi", k.args[0])
1668-
try:
1669-
1/0
1670-
except Exception as e:
1671-
tb = e.__traceback__
1672-
with self.assertRaises(ValueError):
1673-
_testcapi.err_restore(ValueError, 1, tb)
1674-
with self.assertRaises(TypeError):
1675-
_testcapi.err_restore(ValueError, 1, 0)
1676-
try:
1677-
_testcapi.err_restore(ValueError, 1, tb)
1678-
except ValueError as v:
1679-
self.assertEqual(1, v.args[0])
1680-
self.assertIs(tb, v.__traceback__.tb_next)
1681-
1682-
16831558
if __name__ == "__main__":
16841559
unittest.main()

Modules/Setup.stdlib.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
170170
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
171171
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
172-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c
172+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c
173173
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
174174

175175
# Some testing modules MUST be built as shared libraries.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy