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