diff options
author | Collin Winter <collinw@gmail.com> | 2007-03-21 02:57:17 (GMT) |
---|---|---|
committer | Collin Winter <collinw@gmail.com> | 2007-03-21 02:57:17 (GMT) |
commit | 670e6921349dd408b6958a0c5d3b1486725f9beb (patch) | |
tree | 719d6b0e5348693a2d985dfabc5e9160f7f79108 /Lib | |
parent | 450ee81b227b093eeb0b7a933fe6ddc6dc768d4a (diff) | |
download | cpython-670e6921349dd408b6958a0c5d3b1486725f9beb.zip cpython-670e6921349dd408b6958a0c5d3b1486725f9beb.tar.gz cpython-670e6921349dd408b6958a0c5d3b1486725f9beb.tar.bz2 |
Patch #1680961: remove sys.exitfunc and replace it with a private C API. Also, reimplement atexit in C so it can take advantage of this private API.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/atexit.py | 65 | ||||
-rw-r--r-- | Lib/test/test___all__.py | 1 | ||||
-rw-r--r-- | Lib/test/test_atexit.py | 173 |
3 files changed, 94 insertions, 145 deletions
diff --git a/Lib/atexit.py b/Lib/atexit.py deleted file mode 100644 index 51a153e..0000000 --- a/Lib/atexit.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -atexit.py - allow programmer to define multiple exit functions to be executed -upon normal program termination. - -One public function, register, is defined. -""" - -__all__ = ["register"] - -import sys - -_exithandlers = [] -def _run_exitfuncs(): - """run any registered exit functions - - _exithandlers is traversed in reverse order so functions are executed - 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 traceback - print("Error in atexit._run_exitfuncs:", file=sys.stderr) - 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 - - func - function to be called at exit - targs - optional arguments to pass to func - kargs - optional keyword arguments to pass to func - - func is returned to facilitate usage as a decorator. - """ - _exithandlers.append((func, targs, kargs)) - return func - -if hasattr(sys, "exitfunc"): - # Assume it's another registered exit function - append it to our list - register(sys.exitfunc) -sys.exitfunc = _run_exitfuncs - -if __name__ == "__main__": - def x1(): - print("running x1") - def x2(n): - print("running x2(%r)" % (n,)) - def x3(n, kwd=None): - print("running x3(%r, kwd=%r)" % (n, kwd)) - - register(x1) - register(x2, 12) - register(x3, 5, "bar") - register(x3, "no kwd args") diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py index d8e850a..bb1fd8d 100644 --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -48,7 +48,6 @@ class AllTest(unittest.TestCase): self.check_all("StringIO") self.check_all("UserString") self.check_all("aifc") - self.check_all("atexit") self.check_all("audiodev") self.check_all("base64") self.check_all("bdb") diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py index 9d1e003..56077e7 100644 --- a/Lib/test/test_atexit.py +++ b/Lib/test/test_atexit.py @@ -4,97 +4,112 @@ import StringIO import atexit from test import test_support -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") +### helpers +def h1(): + print("h1") - 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") +def h2(): + print("h2") - 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") +def h3(): + print("h3") - 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 +def h4(*args, **kwargs): + print("h4", args, kwargs) + +def raise1(): + raise TypeError - ### helpers - def h1(self): - print("h1") +def raise2(): + raise SystemError - def h2(self): - print("h2") +class TestCase(unittest.TestCase): + def setUp(self): + self.stream = StringIO.StringIO() + sys.stdout = sys.stderr = self.stream + atexit._clear() + + def tearDown(self): + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + atexit._clear() - def h3(self): - print("h3") + def test_args(self): + # be sure args are handled properly + atexit.register(h1) + atexit.register(h4) + atexit.register(h4, 4, kw="abc") + atexit._run_exitfuncs() - def h4(self, *args, **kwargs): - print("h4", args, kwargs) + self.assertEqual(self.stream.getvalue(), + "h4 (4,) {'kw': 'abc'}\nh4 () {}\nh1\n") - def raise1(self): - raise TypeError + def test_order(self): + # be sure handlers are executed in reverse order + atexit.register(h1) + atexit.register(h2) + atexit.register(h3) + atexit._run_exitfuncs() + + self.assertEqual(self.stream.getvalue(), "h3\nh2\nh1\n") - def raise2(self): - raise SystemError + def test_raise(self): + # be sure raises are handled properly + atexit.register(raise1) + atexit.register(raise2) + + self.assertRaises(TypeError, atexit._run_exitfuncs) + + def test_stress(self): + a = [0] + def inc(): + a[0] += 1 + + for i in range(128): + atexit.register(inc) + atexit._run_exitfuncs() + + self.assertEqual(a[0], 128) + + def test_clear(self): + a = [0] + def inc(): + a[0] += 1 + + atexit.register(inc) + atexit._clear() + atexit._run_exitfuncs() + + self.assertEqual(a[0], 0) + + def test_unregister(self): + a = [0] + def inc(): + a[0] += 1 + def dec(): + a[0] -= 1 + + for i in range(4): + atexit.register(inc) + atexit.register(dec) + atexit.unregister(inc) + atexit._run_exitfuncs() + + self.assertEqual(a[0], -1) + + def test_bound_methods(self): + l = [] + atexit.register(l.append, 5) + atexit._run_exitfuncs() + self.assertEqual(l, [5]) + + atexit.unregister(l.append) + atexit._run_exitfuncs() + self.assertEqual(l, [5]) + def test_main(): test_support.run_unittest(TestCase) - if __name__ == "__main__": test_main() |