Fix bug 1052242. Also includes rewrite of test case using unittest and
avoiding use of popen.
This commit is contained in:
parent
ed306292d6
commit
599bd5e1e1
|
@ -39,6 +39,12 @@ completes), all functions registered are called in last in, first out
|
|||
order. The assumption is that lower level modules will normally be
|
||||
imported before higher level modules and thus must be cleaned up
|
||||
later.
|
||||
|
||||
If an exception is raised during execution of the exit handlers, a traceback
|
||||
is printed (unless SystemExit is raised) and the exception information is
|
||||
saved. After all exit handlers have had a chance to run the last exception
|
||||
to be raised is reraised.
|
||||
|
||||
\end{funcdesc}
|
||||
|
||||
|
||||
|
|
|
@ -15,9 +15,22 @@ def _run_exitfuncs():
|
|||
last in, first out.
|
||||
"""
|
||||
|
||||
exc_info = None
|
||||
while _exithandlers:
|
||||
func, targs, kargs = _exithandlers.pop()
|
||||
try:
|
||||
func(*targs, **kargs)
|
||||
except SystemExit:
|
||||
exc_info = sys.exc_info()
|
||||
except:
|
||||
import sys, traceback
|
||||
print >> sys.stderr, "Error in atexit._run_exitfuncs:"
|
||||
traceback.print_exc()
|
||||
exc_info = sys.exc_info()
|
||||
|
||||
if exc_info is not None:
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
|
||||
|
||||
def register(func, *targs, **kargs):
|
||||
"""register a function to be executed upon normal program termination
|
||||
|
@ -33,7 +46,6 @@ if hasattr(sys, "exitfunc"):
|
|||
# Assume it's another registered exit function - append it to our list
|
||||
register(sys.exitfunc)
|
||||
sys.exitfunc = _run_exitfuncs
|
||||
|
||||
del sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1,66 +1,100 @@
|
|||
# Test the atexit module.
|
||||
from test.test_support import TESTFN, vereq, is_jython
|
||||
import atexit
|
||||
from os import popen, unlink
|
||||
import sys
|
||||
|
||||
executable = sys.executable
|
||||
if is_jython:
|
||||
executable = "jython"
|
||||
|
||||
input = """\
|
||||
import unittest
|
||||
import StringIO
|
||||
import atexit
|
||||
from test import test_support
|
||||
|
||||
def handler1():
|
||||
print "handler1"
|
||||
class TestCase(unittest.TestCase):
|
||||
def test_args(self):
|
||||
# be sure args are handled properly
|
||||
s = StringIO.StringIO()
|
||||
sys.stdout = sys.stderr = s
|
||||
save_handlers = atexit._exithandlers
|
||||
atexit._exithandlers = []
|
||||
try:
|
||||
atexit.register(self.h1)
|
||||
atexit.register(self.h4)
|
||||
atexit.register(self.h4, 4, kw="abc")
|
||||
atexit._run_exitfuncs()
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
atexit._exithandlers = save_handlers
|
||||
self.assertEqual(s.getvalue(), "h4 (4,) {'kw': 'abc'}\nh4 () {}\nh1\n")
|
||||
|
||||
def handler2(*args, **kargs):
|
||||
print "handler2", args, kargs
|
||||
def test_order(self):
|
||||
# be sure handlers are executed in reverse order
|
||||
s = StringIO.StringIO()
|
||||
sys.stdout = sys.stderr = s
|
||||
save_handlers = atexit._exithandlers
|
||||
atexit._exithandlers = []
|
||||
try:
|
||||
atexit.register(self.h1)
|
||||
atexit.register(self.h2)
|
||||
atexit.register(self.h3)
|
||||
atexit._run_exitfuncs()
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
atexit._exithandlers = save_handlers
|
||||
self.assertEqual(s.getvalue(), "h3\nh2\nh1\n")
|
||||
|
||||
atexit.register(handler1)
|
||||
atexit.register(handler2)
|
||||
atexit.register(handler2, 7, kw="abc")
|
||||
"""
|
||||
def test_sys_override(self):
|
||||
# be sure a preset sys.exitfunc is handled properly
|
||||
s = StringIO.StringIO()
|
||||
sys.stdout = sys.stderr = s
|
||||
save_handlers = atexit._exithandlers
|
||||
atexit._exithandlers = []
|
||||
exfunc = sys.exitfunc
|
||||
sys.exitfunc = self.h1
|
||||
reload(atexit)
|
||||
try:
|
||||
atexit.register(self.h2)
|
||||
atexit._run_exitfuncs()
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
atexit._exithandlers = save_handlers
|
||||
sys.exitfunc = exfunc
|
||||
self.assertEqual(s.getvalue(), "h2\nh1\n")
|
||||
|
||||
fname = TESTFN + ".py"
|
||||
f = file(fname, "w")
|
||||
f.write(input)
|
||||
f.close()
|
||||
def test_raise(self):
|
||||
# be sure raises are handled properly
|
||||
s = StringIO.StringIO()
|
||||
sys.stdout = sys.stderr = s
|
||||
save_handlers = atexit._exithandlers
|
||||
atexit._exithandlers = []
|
||||
try:
|
||||
atexit.register(self.raise1)
|
||||
atexit.register(self.raise2)
|
||||
self.assertRaises(TypeError, atexit._run_exitfuncs)
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
atexit._exithandlers = save_handlers
|
||||
|
||||
p = popen('"%s" %s' % (executable, fname))
|
||||
output = p.read()
|
||||
p.close()
|
||||
vereq(output, """\
|
||||
handler2 (7,) {'kw': 'abc'}
|
||||
handler2 () {}
|
||||
handler1
|
||||
""")
|
||||
### helpers
|
||||
def h1(self):
|
||||
print "h1"
|
||||
|
||||
input = """\
|
||||
def direct():
|
||||
print "direct exit"
|
||||
def h2(self):
|
||||
print "h2"
|
||||
|
||||
import sys
|
||||
sys.exitfunc = direct
|
||||
def h3(self):
|
||||
print "h3"
|
||||
|
||||
# Make sure atexit doesn't drop
|
||||
def indirect():
|
||||
print "indirect exit"
|
||||
def h4(self, *args, **kwargs):
|
||||
print "h4", args, kwargs
|
||||
|
||||
import atexit
|
||||
atexit.register(indirect)
|
||||
"""
|
||||
def raise1(self):
|
||||
raise TypeError
|
||||
|
||||
f = file(fname, "w")
|
||||
f.write(input)
|
||||
f.close()
|
||||
def raise2(self):
|
||||
raise SystemError
|
||||
|
||||
p = popen('"%s" %s' % (executable, fname))
|
||||
output = p.read()
|
||||
p.close()
|
||||
vereq(output, """\
|
||||
indirect exit
|
||||
direct exit
|
||||
""")
|
||||
def test_main():
|
||||
test_support.run_unittest(TestCase)
|
||||
|
||||
unlink(fname)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
||||
|
|
11
Misc/NEWS
11
Misc/NEWS
|
@ -2,6 +2,17 @@
|
|||
Python News
|
||||
+++++++++++
|
||||
|
||||
What's New in Python 2.4 release candidate 1?
|
||||
=============================================
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
- Bug 1052242: If exceptions are raised by an atexit handler function an
|
||||
attempt is made to execute the remaining handlers. The last exception
|
||||
raised is re-raised.
|
||||
|
||||
|
||||
(editors: check NEWS.help for information about editing NEWS using ReST.)
|
||||
|
||||
What's New in Python 2.4 beta 2?
|
||||
|
|
Loading…
Reference in New Issue