1- import sys
2- import unittest
3- import io
41import atexit
52import os
3+ import sys
4+ import textwrap
5+ import unittest
66from test import support
77from test .support import script_helper
88
9- ### helpers
10- def h1 ():
11- print ("h1" )
12-
13- def h2 ():
14- print ("h2" )
15-
16- def h3 ():
17- print ("h3" )
18-
19- def h4 (* args , ** kwargs ):
20- print ("h4" , args , kwargs )
21-
22- def raise1 ():
23- raise TypeError
24-
25- def raise2 ():
26- raise SystemError
27-
28- def exit ():
29- raise SystemExit
30-
319
3210class GeneralTest (unittest .TestCase ):
11+ def test_general (self ):
12+ # Run _test_atexit.py in a subprocess since it calls atexit._clear()
13+ script = support .findfile ("_test_atexit.py" )
14+ script_helper .run_test_script (script )
3315
34- def setUp (self ):
35- self .save_stdout = sys .stdout
36- self .save_stderr = sys .stderr
37- self .stream = io .StringIO ()
38- sys .stdout = sys .stderr = self .stream
39- atexit ._clear ()
40-
41- def tearDown (self ):
42- sys .stdout = self .save_stdout
43- sys .stderr = self .save_stderr
44- atexit ._clear ()
45-
46- def test_args (self ):
47- # be sure args are handled properly
48- atexit .register (h1 )
49- atexit .register (h4 )
50- atexit .register (h4 , 4 , kw = "abc" )
51- atexit ._run_exitfuncs ()
52-
53- self .assertEqual (self .stream .getvalue (),
54- "h4 (4,) {'kw': 'abc'}\n h4 () {}\n h1\n " )
55-
56- def test_badargs (self ):
57- atexit .register (lambda : 1 , 0 , 0 , (x for x in (1 ,2 )), 0 , 0 )
58- self .assertRaises (TypeError , atexit ._run_exitfuncs )
59-
60- def test_order (self ):
61- # be sure handlers are executed in reverse order
62- atexit .register (h1 )
63- atexit .register (h2 )
64- atexit .register (h3 )
65- atexit ._run_exitfuncs ()
66-
67- self .assertEqual (self .stream .getvalue (), "h3\n h2\n h1\n " )
68-
69- def test_raise (self ):
70- # be sure raises are handled properly
71- atexit .register (raise1 )
72- atexit .register (raise2 )
73-
74- self .assertRaises (TypeError , atexit ._run_exitfuncs )
75-
76- def test_raise_unnormalized (self ):
77- # Issue #10756: Make sure that an unnormalized exception is
78- # handled properly
79- atexit .register (lambda : 1 / 0 )
80-
81- self .assertRaises (ZeroDivisionError , atexit ._run_exitfuncs )
82- self .assertIn ("ZeroDivisionError" , self .stream .getvalue ())
83-
84- def test_exit (self ):
85- # be sure a SystemExit is handled properly
86- atexit .register (exit )
87-
88- self .assertRaises (SystemExit , atexit ._run_exitfuncs )
89- self .assertEqual (self .stream .getvalue (), '' )
90-
91- def test_print_tracebacks (self ):
92- # Issue #18776: the tracebacks should be printed when errors occur.
93- def f ():
94- 1 / 0 # one
95- def g ():
96- 1 / 0 # two
97- def h ():
98- 1 / 0 # three
99- atexit .register (f )
100- atexit .register (g )
101- atexit .register (h )
102-
103- self .assertRaises (ZeroDivisionError , atexit ._run_exitfuncs )
104- stderr = self .stream .getvalue ()
105- self .assertEqual (stderr .count ("ZeroDivisionError" ), 3 )
106- self .assertIn ("# one" , stderr )
107- self .assertIn ("# two" , stderr )
108- self .assertIn ("# three" , stderr )
109-
110- def test_stress (self ):
111- a = [0 ]
112- def inc ():
113- a [0 ] += 1
114-
115- for i in range (128 ):
116- atexit .register (inc )
117- atexit ._run_exitfuncs ()
118-
119- self .assertEqual (a [0 ], 128 )
120-
121- def test_clear (self ):
122- a = [0 ]
123- def inc ():
124- a [0 ] += 1
125-
126- atexit .register (inc )
127- atexit ._clear ()
128- atexit ._run_exitfuncs ()
129-
130- self .assertEqual (a [0 ], 0 )
131-
132- def test_unregister (self ):
133- a = [0 ]
134- def inc ():
135- a [0 ] += 1
136- def dec ():
137- a [0 ] -= 1
138-
139- for i in range (4 ):
140- atexit .register (inc )
141- atexit .register (dec )
142- atexit .unregister (inc )
143- atexit ._run_exitfuncs ()
144-
145- self .assertEqual (a [0 ], - 1 )
146-
147- def test_bound_methods (self ):
148- l = []
149- atexit .register (l .append , 5 )
150- atexit ._run_exitfuncs ()
151- self .assertEqual (l , [5 ])
152-
153- atexit .unregister (l .append )
154- atexit ._run_exitfuncs ()
155- self .assertEqual (l , [5 ])
156-
16+ class FunctionalTest (unittest .TestCase ):
15717 def test_shutdown (self ):
15818 # Actually test the shutdown mechanism in a subprocess
159- code = """if 1:
19+ code = textwrap . dedent ( """
16020 import atexit
16121
16222 def f(msg):
16323 print(msg)
16424
16525 atexit.register(f, "one")
16626 atexit.register(f, "two")
167- """
27+ """ )
16828 res = script_helper .assert_python_ok ("-c" , code )
16929 self .assertEqual (res .out .decode ().splitlines (), ["two" , "one" ])
17030 self .assertFalse (res .err )
17131
32+ def test_atexit_instances (self ):
33+ # bpo-42639: It is safe to have more than one atexit instance.
34+ code = textwrap .dedent ("""
35+ import sys
36+ import atexit as atexit1
37+ del sys.modules['atexit']
38+ import atexit as atexit2
39+ del sys.modules['atexit']
40+
41+ assert atexit2 is not atexit1
42+
43+ atexit1.register(print, "atexit1")
44+ atexit2.register(print, "atexit2")
45+ """ )
46+ res = script_helper .assert_python_ok ("-c" , code )
47+ self .assertEqual (res .out .decode ().splitlines (), ["atexit2" , "atexit1" ])
48+ self .assertFalse (res .err )
49+
17250
17351@support .cpython_only
17452class SubinterpreterTest (unittest .TestCase ):
@@ -178,13 +56,13 @@ def test_callbacks_leak(self):
17856 # take care to free callbacks in its per-subinterpreter module
17957 # state.
18058 n = atexit ._ncallbacks ()
181- code = r"""if 1:
59+ code = textwrap . dedent ( r"""
18260 import atexit
18361 def f():
18462 pass
18563 atexit.register(f)
18664 del atexit
187- """
65+ """ )
18866 ret = support .run_in_subinterp (code )
18967 self .assertEqual (ret , 0 )
19068 self .assertEqual (atexit ._ncallbacks (), n )
@@ -193,13 +71,13 @@ def test_callbacks_leak_refcycle(self):
19371 # Similar to the above, but with a refcycle through the atexit
19472 # module.
19573 n = atexit ._ncallbacks ()
196- code = r"""if 1:
74+ code = textwrap . dedent ( r"""
19775 import atexit
19876 def f():
19977 pass
20078 atexit.register(f)
20179 atexit.__atexit = atexit
202- """
80+ """ )
20381 ret = support .run_in_subinterp (code )
20482 self .assertEqual (ret , 0 )
20583 self .assertEqual (atexit ._ncallbacks (), n )
@@ -210,13 +88,13 @@ def test_callback_on_subinterpreter_teardown(self):
21088 expected = b"The test has passed!"
21189 r , w = os .pipe ()
21290
213- code = r"""if 1:
91+ code = textwrap . dedent ( r"""
21492 import os
21593 import atexit
21694 def callback():
21795 os.write({:d}, b"The test has passed!")
21896 atexit.register(callback)
219- """ .format (w )
97+ """ .format (w ))
22098 ret = support .run_in_subinterp (code )
22199 os .close (w )
222100 self .assertEqual (os .read (r , len (expected )), expected )
0 commit comments