1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
"""
Tests run by test_atexit in a subprocess since it clears atexit callbacks.
"""
import atexit
import sys
import unittest
from test import support
class GeneralTest(unittest.TestCase):
def setUp(self):
atexit._clear()
def tearDown(self):
atexit._clear()
def assert_raises_unraisable(self, exc_type, func, *args):
with support.catch_unraisable_exception() as cm:
atexit.register(func, *args)
atexit._run_exitfuncs()
self.assertIsNone(cm.unraisable.object)
self.assertEqual(cm.unraisable.err_msg,
f'Exception ignored in atexit callback {func!r}')
self.assertEqual(cm.unraisable.exc_type, exc_type)
self.assertEqual(type(cm.unraisable.exc_value), exc_type)
def test_order(self):
# Check that callbacks are called in reverse order with the expected
# positional and keyword arguments.
calls = []
def func1(*args, **kwargs):
calls.append(('func1', args, kwargs))
def func2(*args, **kwargs):
calls.append(('func2', args, kwargs))
# be sure args are handled properly
atexit.register(func1, 1, 2)
atexit.register(func2)
atexit.register(func2, 3, key="value")
atexit._run_exitfuncs()
self.assertEqual(calls,
[('func2', (3,), {'key': 'value'}),
('func2', (), {}),
('func1', (1, 2), {})])
def test_badargs(self):
def func():
pass
# func() has no parameter, but it's called with 2 parameters
self.assert_raises_unraisable(TypeError, func, 1 ,2)
def test_raise(self):
def raise_type_error():
raise TypeError
self.assert_raises_unraisable(TypeError, raise_type_error)
def test_raise_unnormalized(self):
# bpo-10756: Make sure that an unnormalized exception is handled
# properly.
def div_zero():
1 / 0
self.assert_raises_unraisable(ZeroDivisionError, div_zero)
def test_exit(self):
self.assert_raises_unraisable(SystemExit, sys.exit)
def test_stress(self):
a = [0]
def inc():
a[0] += 1
for i in range(128):
atexit.register(inc)
atexit._run_exitfuncs()
self.assertEqual(a[0], 128)
def test_clear(self):
a = [0]
def inc():
a[0] += 1
atexit.register(inc)
atexit._clear()
atexit._run_exitfuncs()
self.assertEqual(a[0], 0)
def test_unregister(self):
a = [0]
def inc():
a[0] += 1
def dec():
a[0] -= 1
for i in range(4):
atexit.register(inc)
atexit.register(dec)
atexit.unregister(inc)
atexit._run_exitfuncs()
self.assertEqual(a[0], -1)
def test_bound_methods(self):
l = []
atexit.register(l.append, 5)
atexit._run_exitfuncs()
self.assertEqual(l, [5])
atexit.unregister(l.append)
atexit._run_exitfuncs()
self.assertEqual(l, [5])
def test_atexit_with_unregistered_function(self):
# See bpo-46025 for more info
def func():
atexit.unregister(func)
1/0
atexit.register(func)
try:
with support.catch_unraisable_exception() as cm:
atexit._run_exitfuncs()
self.assertIsNone(cm.unraisable.object)
self.assertEqual(cm.unraisable.err_msg,
f'Exception ignored in atexit callback {func!r}')
self.assertEqual(cm.unraisable.exc_type, ZeroDivisionError)
self.assertEqual(type(cm.unraisable.exc_value), ZeroDivisionError)
finally:
atexit.unregister(func)
if __name__ == "__main__":
unittest.main()
|