blob: 29faaaf0a9d80e158569fa1a62843c4fdde64baf [file] [log] [blame]
Fred Drakec19425d2000-06-28 15:07:31 +00001import atexit
Victor Stinner83d52042020-12-14 22:40:40 +01002import io
Marcel Plch776407f2017-12-20 11:17:58 +01003import os
Victor Stinner83d52042020-12-14 22:40:40 +01004import sys
5import textwrap
6import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007from test import support
Antoine Pitroufc5db952017-12-13 02:29:07 +01008from test.support import script_helper
Fred Drakec19425d2000-06-28 15:07:31 +00009
Collin Winter670e6922007-03-21 02:57:17 +000010### helpers
11def h1():
12 print("h1")
13
14def h2():
15 print("h2")
16
17def h3():
18 print("h3")
19
20def h4(*args, **kwargs):
21 print("h4", args, kwargs)
22
23def raise1():
24 raise TypeError
25
26def raise2():
27 raise SystemError
28
Serhiy Storchaka3fd54d42017-06-12 08:25:04 +030029def exit():
30 raise SystemExit
31
Antoine Pitrou2d350fd2013-08-01 20:56:12 +020032
33class GeneralTest(unittest.TestCase):
34
Collin Winter670e6922007-03-21 02:57:17 +000035 def setUp(self):
Victor Stinner457ab062011-01-05 23:47:00 +000036 self.save_stdout = sys.stdout
37 self.save_stderr = sys.stderr
Guido van Rossum34d19282007-08-09 01:03:29 +000038 self.stream = io.StringIO()
Collin Winter670e6922007-03-21 02:57:17 +000039 sys.stdout = sys.stderr = self.stream
40 atexit._clear()
Guido van Rossumd8faa362007-04-27 19:54:29 +000041
Collin Winter670e6922007-03-21 02:57:17 +000042 def tearDown(self):
Benjamin Petersonf10a79a2008-10-11 00:49:57 +000043 sys.stdout = self.save_stdout
44 sys.stderr = self.save_stderr
Collin Winter670e6922007-03-21 02:57:17 +000045 atexit._clear()
46
Skip Montanaro599bd5e2004-11-04 04:31:30 +000047 def test_args(self):
48 # be sure args are handled properly
Collin Winter670e6922007-03-21 02:57:17 +000049 atexit.register(h1)
50 atexit.register(h4)
51 atexit.register(h4, 4, kw="abc")
52 atexit._run_exitfuncs()
53
54 self.assertEqual(self.stream.getvalue(),
55 "h4 (4,) {'kw': 'abc'}\nh4 () {}\nh1\n")
Fred Drakec19425d2000-06-28 15:07:31 +000056
Benjamin Petersonb8401c72008-09-23 03:14:49 +000057 def test_badargs(self):
58 atexit.register(lambda: 1, 0, 0, (x for x in (1,2)), 0, 0)
59 self.assertRaises(TypeError, atexit._run_exitfuncs)
60
Skip Montanaro599bd5e2004-11-04 04:31:30 +000061 def test_order(self):
62 # be sure handlers are executed in reverse order
Collin Winter670e6922007-03-21 02:57:17 +000063 atexit.register(h1)
64 atexit.register(h2)
65 atexit.register(h3)
66 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +000067
Collin Winter670e6922007-03-21 02:57:17 +000068 self.assertEqual(self.stream.getvalue(), "h3\nh2\nh1\n")
Fred Drakec19425d2000-06-28 15:07:31 +000069
Skip Montanaro599bd5e2004-11-04 04:31:30 +000070 def test_raise(self):
71 # be sure raises are handled properly
Collin Winter670e6922007-03-21 02:57:17 +000072 atexit.register(raise1)
73 atexit.register(raise2)
Guido van Rossumd8faa362007-04-27 19:54:29 +000074
Collin Winter670e6922007-03-21 02:57:17 +000075 self.assertRaises(TypeError, atexit._run_exitfuncs)
Guido van Rossumd8faa362007-04-27 19:54:29 +000076
Victor Stinner358e11d2011-01-05 03:54:25 +000077 def test_raise_unnormalized(self):
78 # Issue #10756: Make sure that an unnormalized exception is
79 # handled properly
80 atexit.register(lambda: 1 / 0)
81
82 self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
83 self.assertIn("ZeroDivisionError", self.stream.getvalue())
84
Serhiy Storchaka3fd54d42017-06-12 08:25:04 +030085 def test_exit(self):
86 # be sure a SystemExit is handled properly
87 atexit.register(exit)
88
89 self.assertRaises(SystemExit, atexit._run_exitfuncs)
90 self.assertEqual(self.stream.getvalue(), '')
91
Antoine Pitrou24201d42013-10-13 21:53:13 +020092 def test_print_tracebacks(self):
93 # Issue #18776: the tracebacks should be printed when errors occur.
94 def f():
95 1/0 # one
96 def g():
97 1/0 # two
98 def h():
99 1/0 # three
100 atexit.register(f)
101 atexit.register(g)
102 atexit.register(h)
103
104 self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
105 stderr = self.stream.getvalue()
106 self.assertEqual(stderr.count("ZeroDivisionError"), 3)
107 self.assertIn("# one", stderr)
108 self.assertIn("# two", stderr)
109 self.assertIn("# three", stderr)
110
Collin Winter670e6922007-03-21 02:57:17 +0000111 def test_stress(self):
112 a = [0]
113 def inc():
114 a[0] += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000115
Collin Winter670e6922007-03-21 02:57:17 +0000116 for i in range(128):
117 atexit.register(inc)
118 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000119
Collin Winter670e6922007-03-21 02:57:17 +0000120 self.assertEqual(a[0], 128)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000121
Collin Winter670e6922007-03-21 02:57:17 +0000122 def test_clear(self):
123 a = [0]
124 def inc():
125 a[0] += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000126
Collin Winter670e6922007-03-21 02:57:17 +0000127 atexit.register(inc)
128 atexit._clear()
129 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000130
Collin Winter670e6922007-03-21 02:57:17 +0000131 self.assertEqual(a[0], 0)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000132
Collin Winter670e6922007-03-21 02:57:17 +0000133 def test_unregister(self):
134 a = [0]
135 def inc():
136 a[0] += 1
137 def dec():
138 a[0] -= 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000139
140 for i in range(4):
Collin Winter670e6922007-03-21 02:57:17 +0000141 atexit.register(inc)
142 atexit.register(dec)
143 atexit.unregister(inc)
144 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000145
Collin Winter670e6922007-03-21 02:57:17 +0000146 self.assertEqual(a[0], -1)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000147
Collin Winter670e6922007-03-21 02:57:17 +0000148 def test_bound_methods(self):
149 l = []
150 atexit.register(l.append, 5)
151 atexit._run_exitfuncs()
152 self.assertEqual(l, [5])
Guido van Rossumd8faa362007-04-27 19:54:29 +0000153
Collin Winter670e6922007-03-21 02:57:17 +0000154 atexit.unregister(l.append)
155 atexit._run_exitfuncs()
156 self.assertEqual(l, [5])
Guido van Rossumd8faa362007-04-27 19:54:29 +0000157
Antoine Pitroufc5db952017-12-13 02:29:07 +0100158 def test_shutdown(self):
159 # Actually test the shutdown mechanism in a subprocess
Victor Stinner83d52042020-12-14 22:40:40 +0100160 code = textwrap.dedent("""
Antoine Pitroufc5db952017-12-13 02:29:07 +0100161 import atexit
162
163 def f(msg):
164 print(msg)
165
166 atexit.register(f, "one")
167 atexit.register(f, "two")
Victor Stinner83d52042020-12-14 22:40:40 +0100168 """)
Antoine Pitroufc5db952017-12-13 02:29:07 +0100169 res = script_helper.assert_python_ok("-c", code)
170 self.assertEqual(res.out.decode().splitlines(), ["two", "one"])
171 self.assertFalse(res.err)
172
Victor Stinnerb8fa1352020-12-15 14:34:19 +0100173 def test_atexit_instances(self):
174 # bpo-42639: It is safe to have more than one atexit instance.
175 code = textwrap.dedent("""
176 import sys
177 import atexit as atexit1
178 del sys.modules['atexit']
179 import atexit as atexit2
180 del sys.modules['atexit']
181
182 assert atexit2 is not atexit1
183
184 atexit1.register(print, "atexit1")
185 atexit2.register(print, "atexit2")
186 """)
187 res = script_helper.assert_python_ok("-c", code)
188 self.assertEqual(res.out.decode().splitlines(), ["atexit2", "atexit1"])
189 self.assertFalse(res.err)
190
Tim Peters012b69c2002-07-16 19:30:59 +0000191
Serhiy Storchaka24c738a2017-03-19 20:20:10 +0200192@support.cpython_only
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200193class SubinterpreterTest(unittest.TestCase):
194
195 def test_callbacks_leak(self):
196 # This test shows a leak in refleak mode if atexit doesn't
197 # take care to free callbacks in its per-subinterpreter module
198 # state.
199 n = atexit._ncallbacks()
Victor Stinner83d52042020-12-14 22:40:40 +0100200 code = textwrap.dedent(r"""
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200201 import atexit
202 def f():
203 pass
204 atexit.register(f)
205 del atexit
Victor Stinner83d52042020-12-14 22:40:40 +0100206 """)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100207 ret = support.run_in_subinterp(code)
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200208 self.assertEqual(ret, 0)
209 self.assertEqual(atexit._ncallbacks(), n)
210
211 def test_callbacks_leak_refcycle(self):
212 # Similar to the above, but with a refcycle through the atexit
213 # module.
214 n = atexit._ncallbacks()
Victor Stinner83d52042020-12-14 22:40:40 +0100215 code = textwrap.dedent(r"""
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200216 import atexit
217 def f():
218 pass
219 atexit.register(f)
220 atexit.__atexit = atexit
Victor Stinner83d52042020-12-14 22:40:40 +0100221 """)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100222 ret = support.run_in_subinterp(code)
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200223 self.assertEqual(ret, 0)
224 self.assertEqual(atexit._ncallbacks(), n)
225
Marcel Plch776407f2017-12-20 11:17:58 +0100226 def test_callback_on_subinterpreter_teardown(self):
227 # This tests if a callback is called on
228 # subinterpreter teardown.
229 expected = b"The test has passed!"
230 r, w = os.pipe()
231
Victor Stinner83d52042020-12-14 22:40:40 +0100232 code = textwrap.dedent(r"""
Marcel Plch776407f2017-12-20 11:17:58 +0100233 import os
234 import atexit
235 def callback():
236 os.write({:d}, b"The test has passed!")
237 atexit.register(callback)
Victor Stinner83d52042020-12-14 22:40:40 +0100238 """.format(w))
Marcel Plch776407f2017-12-20 11:17:58 +0100239 ret = support.run_in_subinterp(code)
240 os.close(w)
241 self.assertEqual(os.read(r, len(expected)), expected)
242 os.close(r)
243
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200244
Skip Montanaro599bd5e2004-11-04 04:31:30 +0000245if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500246 unittest.main()