diff options
-rw-r--r-- | Doc/Makefile.deps | 1 | ||||
-rw-r--r-- | Doc/lib/lib.tex | 1 | ||||
-rw-r--r-- | Doc/lib/libatexit.tex | 59 | ||||
-rw-r--r-- | Doc/lib/libsys.tex | 4 | ||||
-rw-r--r-- | Lib/atexit.py | 54 | ||||
-rw-r--r-- | Lib/test/output/test_atexit | 4 | ||||
-rw-r--r-- | Lib/test/test_atexit.py | 24 |
7 files changed, 146 insertions, 1 deletions
diff --git a/Doc/Makefile.deps b/Doc/Makefile.deps index b6a127f..2ad97e9 100644 --- a/Doc/Makefile.deps +++ b/Doc/Makefile.deps @@ -228,6 +228,7 @@ LIBFILES= $(MANSTYLES) $(COMMONTEX) \ ../lib/libstatvfs.tex \ ../lib/libtty.tex \ ../lib/libasyncore.tex \ + ../lib/libatexit.tex \ ../lib/libcfgparser.tex # LaTeX source files for Macintosh Library Modules. diff --git a/Doc/lib/lib.tex b/Doc/lib/lib.tex index b426a6a..3e60b9b 100644 --- a/Doc/lib/lib.tex +++ b/Doc/lib/lib.tex @@ -73,6 +73,7 @@ and how to embed it in other applications. \input{libpython} % Python Services \input{libsys} +\input{libatexit} \input{libtypes} \input{libuserdict} \input{liboperator} diff --git a/Doc/lib/libatexit.tex b/Doc/lib/libatexit.tex new file mode 100644 index 0000000..9d0b48c --- /dev/null +++ b/Doc/lib/libatexit.tex @@ -0,0 +1,59 @@ +\section{\module{atexit} --- + exit handlers} + +\declaremodule{standard}{atexit} +\moduleauthor{Skip Montanaro}{skip@mojam.com} +\sectionauthor{Skip Montanaro}{skip@mojam.com} +\modulesynopsis{Register and execute cleanup functions.} + +The \module{atexit} module defines a single function to register +cleanup functions. Functions thus registered are automatically +executed upon normal interpreter termination. + +Note: the functions registered via this module are not called when the program is killed by a +signal, when a Python fatal internal error is detected, or when +\code{os._exit()} is called. + +This is an alternate interface to the functionality provided by the +\code{sys.exitfunc} variable. +\withsubitem{(in sys)}{\ttindex{exitfunc}} + +\begin{funcdesc}{register}{func\optional{, *args\optional{, **kargs}}} +Register \var{func} as a function to be executed at termination. Any +optional arguments that are to be passed to \var{func} must be passed +as arguments to \function{register()}. + +At normal program termination (for instance, if +\function{sys.exit()} is called or the main module's execution +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. +\end{funcdesc} + + +\subsection{\module{atexit} Example \label{atexit-example}} + +The following simple example demonstrates how a module can initialize +a counter from a file when it is imported and save the counter's +updated value automatically when the program terminates without +relying on the application making an explicit call into this module at +termination. + +\begin{verbatim} +try: + _count = int(open("/tmp/counter").read()) +except IOError: + _count = 0 + +def incrcounter(n): + global _count + _count = _count + n + +def savecounter(): + open("/tmp/counter", "w").write("%d" % _count) + +import atexit +atexit.register(savecounter) +\end{verbatim} + diff --git a/Doc/lib/libsys.tex b/Doc/lib/libsys.tex index 01887da..9b4f906 100644 --- a/Doc/lib/libsys.tex +++ b/Doc/lib/libsys.tex @@ -127,7 +127,9 @@ way to exit a program when an error occurs. This value is not actually defined by the module, but can be set by the user (or by a program) to specify a clean-up action at program exit. When set, it should be a parameterless function. This function - will be called when the interpreter exits. Note: the exit function + will be called when the interpreter exits. Only one function may be + installed in this way; to allow multiple functions which will be called + at termination, use the \refmodule{atexit} module. Note: the exit function is not called when the program is killed by a signal, when a Python fatal internal error is detected, or when \code{os._exit()} is called. \end{datadesc} diff --git a/Lib/atexit.py b/Lib/atexit.py new file mode 100644 index 0000000..a311630 --- /dev/null +++ b/Lib/atexit.py @@ -0,0 +1,54 @@ +""" +atexit.py - allow programmer to define multiple exit functions to be executed +upon normal program termination. + +One public function, register, is defined. +""" + +_exithandlers = [] +def _run_exitfuncs(): + """run any registered exit functions + + _exithandlers is traversed in reverse order so functions are executed + last in, first out. + """ + + while _exithandlers: + func, targs, kargs = _exithandlers[-1] + apply(func, targs, kargs) + _exithandlers.remove(_exithandlers[-1]) + +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 + """ + _exithandlers.append((func, targs, kargs)) + +import sys +try: + x = sys.exitfunc +except AttributeError: + sys.exitfunc = _run_exitfuncs +else: + # if x isn't our own exit func executive, assume it's another + # registered exit function - append it to our list... + if x != _run_exitfuncs: + register(x) +del sys + +if __name__ == "__main__": + def x1(): + print "running x1" + def x2(n): + print "running x2(%s)" % `n` + def x3(n, kwd=None): + print "running x3(%s, kwd=%s)" % (`n`, `kwd`) + + register(x1) + register(x2, 12) + register(x3, 5, "bar") + register(x3, "no kwd args") + diff --git a/Lib/test/output/test_atexit b/Lib/test/output/test_atexit new file mode 100644 index 0000000..1cc01de --- /dev/null +++ b/Lib/test/output/test_atexit @@ -0,0 +1,4 @@ +test_atexit +handler2 (7,) {'kw': 'abc'} +handler2 () {} +handler1 diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py new file mode 100644 index 0000000..517610b --- /dev/null +++ b/Lib/test/test_atexit.py @@ -0,0 +1,24 @@ +# Test the exit module +from test_support import verbose +import atexit + +def handler1(): + print "handler1" + +def handler2(*args, **kargs): + print "handler2", args, kargs + +# save any exit functions that may have been registered as part of the +# test framework +_exithandlers = atexit._exithandlers +atexit._exithandlers = [] + +atexit.register(handler1) +atexit.register(handler2) +atexit.register(handler2, 7, kw="abc") + +# simulate exit behavior by calling atexit._run_exitfuncs directly... +atexit._run_exitfuncs() + +# restore exit handlers +atexit._exithandlers = _exithandlers |