blob: 906f96dc31af08170d180de0e9bbf1fcada9fff8 [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
Tim Peters012b69c2002-07-16 19:30:59 +0000173
Serhiy Storchaka24c738a2017-03-19 20:20:10 +0200174@support.cpython_only
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200175class SubinterpreterTest(unittest.TestCase):
176
177 def test_callbacks_leak(self):
178 # This test shows a leak in refleak mode if atexit doesn't
179 # take care to free callbacks in its per-subinterpreter module
180 # state.
181 n = atexit._ncallbacks()
Victor Stinner83d52042020-12-14 22:40:40 +0100182 code = textwrap.dedent(r"""
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200183 import atexit
184 def f():
185 pass
186 atexit.register(f)
187 del atexit
Victor Stinner83d52042020-12-14 22:40:40 +0100188 """)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100189 ret = support.run_in_subinterp(code)
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200190 self.assertEqual(ret, 0)
191 self.assertEqual(atexit._ncallbacks(), n)
192
193 def test_callbacks_leak_refcycle(self):
194 # Similar to the above, but with a refcycle through the atexit
195 # module.
196 n = atexit._ncallbacks()
Victor Stinner83d52042020-12-14 22:40:40 +0100197 code = textwrap.dedent(r"""
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200198 import atexit
199 def f():
200 pass
201 atexit.register(f)
202 atexit.__atexit = atexit
Victor Stinner83d52042020-12-14 22:40:40 +0100203 """)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100204 ret = support.run_in_subinterp(code)
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200205 self.assertEqual(ret, 0)
206 self.assertEqual(atexit._ncallbacks(), n)
207
Marcel Plch776407f2017-12-20 11:17:58 +0100208 def test_callback_on_subinterpreter_teardown(self):
209 # This tests if a callback is called on
210 # subinterpreter teardown.
211 expected = b"The test has passed!"
212 r, w = os.pipe()
213
Victor Stinner83d52042020-12-14 22:40:40 +0100214 code = textwrap.dedent(r"""
Marcel Plch776407f2017-12-20 11:17:58 +0100215 import os
216 import atexit
217 def callback():
218 os.write({:d}, b"The test has passed!")
219 atexit.register(callback)
Victor Stinner83d52042020-12-14 22:40:40 +0100220 """.format(w))
Marcel Plch776407f2017-12-20 11:17:58 +0100221 ret = support.run_in_subinterp(code)
222 os.close(w)
223 self.assertEqual(os.read(r, len(expected)), expected)
224 os.close(r)
225
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200226
Skip Montanaro599bd5e2004-11-04 04:31:30 +0000227if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500228 unittest.main()