• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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