[Python-Dev] updated exit.py and supporting files for your perusal

Skip Montanaro skip@mojam.com (Skip Montanaro)
Wed, 21 Jun 2000 13:15:19 -0500 (CDT)


--tqfUNARIjv
Content-Type: text/plain; charset=us-ascii
Content-Description: message body and .signature
Content-Transfer-Encoding: 7bit

This message contains four attached files:

    Lib/exit.py	- a module that allows users to register cleanup functions
    Lib/test/test_exit.py - a simple test script
    Lib/test/output/test_exit - expected test output
    Doc/lib/libexit.tex - library reference manual section

Besides adding documentation and a test script, the following two mods were
made to exit.py since I previously posted it:

    1. It implements a LIFO execution order
    2. If sys.exitfunc is already defined and not exit._run_exitfuncs, it is 
       treated as an exit function and appended to the exit function list.

Comments, please.  Also, can someone tell me how to coax CVS into creating a 
unified diff that actually contains new files?  I tried

    cvs diff -RNau

without success.

Thanks,

-- 
Skip Montanaro, skip@mojam.com, http://www.mojam.com/, http://www.musi-cal.com/
On June 24th at 8AM, live your life for an hour as Ricky Byrdsong always lived
his - run/walk in the Ricky Byrdsong Memorial 5K or just make a donation:
    https://www.SignmeupSports.com/Events/Index_Events.asp?EventID=1395


--tqfUNARIjv
Content-Type: text/plain
Content-Description: Lib/exit.py
Content-Disposition: inline;
	filename="exit.py"
Content-Transfer-Encoding: 7bit

"""
exit.py - allow programmer to define multiple exit functions to be executed
upon normal program termination.

One public function, register_exitfunc, 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_exitfunc(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_exitfunc(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_exitfunc(x1)
    register_exitfunc(x2, 12)
    register_exitfunc(x3, 5, "bar")
    register_exitfunc(x3, "no kwd args")


--tqfUNARIjv
Content-Type: text/plain
Content-Description: Lib/test/test_exit.py
Content-Disposition: inline;
	filename="test_exit.py"
Content-Transfer-Encoding: 7bit

# Test the exit module
from test_support import verbose
import exit

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 = exit._exithandlers
exit._exithandlers = []

exit.register_exitfunc(handler1)
exit.register_exitfunc(handler2)
exit.register_exitfunc(handler2, 7, kw="abc")

# simulate exit behavior by calling exit._run_exitfuncs directly...
exit._run_exitfuncs()

# restore exit handlers
exit._exithandlers = _exithandlers

--tqfUNARIjv
Content-Type: text/plain
Content-Description: Lib/test/output/test_exit
Content-Disposition: inline;
	filename="test_exit"
Content-Transfer-Encoding: 7bit

test_exit
handler2 (7,) {'kw': 'abc'}
handler2 () {}
handler1

--tqfUNARIjv
Content-Type: text/plain
Content-Description: Doc/lib/libexit.tex
Content-Disposition: inline;
	filename="libexit.tex"
Content-Transfer-Encoding: 7bit

\section{\module{exit} ---
         exit handlers}

\declaremodule{standard}{exit}
\sectionauthor{Skip Montanaro}{skip@mojam.com}
\modulesynopsis{Register and execute cleanup functions.}

The \module{exit} module defines a single function to register cleanup
functions.  Functions thus registered are automatically executed upon normal
interpreter termination.

\begin{funcdesc}{register_exitfunc}{func\optional{, *args\optional{,
**kargs}}} Register \code{func} as a function to be executed at termination.
Any optional arguments that are to be passed to func must be passed as
arguments to
\func{register_exitfunc}. 

At normal program termination (for instance, if \func{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.

\subsection{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.

\begin{verbatim}
try:
    _count = eval(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 exit
exit.register_exitfunc(savecounter)
\end{verbatim}


--tqfUNARIjv--