summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorCollin Winter <collinw@gmail.com>2007-03-21 02:57:17 (GMT)
committerCollin Winter <collinw@gmail.com>2007-03-21 02:57:17 (GMT)
commit670e6921349dd408b6958a0c5d3b1486725f9beb (patch)
tree719d6b0e5348693a2d985dfabc5e9160f7f79108 /Lib
parent450ee81b227b093eeb0b7a933fe6ddc6dc768d4a (diff)
downloadcpython-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.py65
-rw-r--r--Lib/test/test___all__.py1
-rw-r--r--Lib/test/test_atexit.py173
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()