| sclapp (version 0.2.3) | index /home/fab/work/projects/software/release/sclapp-0.2.3/sclapp/__init__.py |
an easy-to-use framework for python command line applications
Copyright (c) 2005-2006 Forest Bond.
This file is part of the sclapp software package.
See the COPYING file for the license.
1. Overview
sclapp is a python module providing functionality intended for use by command
line applications. The core functionality provided by the module is activated
by wrapping your application's main function with some sclapp boilerplate code
that initalizes the additional services and handles some internal exceptions
appropriately, without producing a traceback.
sclapp was written primarily because I found myself including most of the same
code in every command line application I was writing. Putting this code in a
separate module makes my life easier, and makes my programs more consistent.
Others may find these benefits to their liking as well, which is why I've made
it available as a separate module.
2. Quick Start
Using sclapp should be fairly straight-forward. Here's the simplest
scenario:
--------------------------------------------------------------------------------
import sclapp
def mymain(argv):
do_something()
main = sclapp.main(mymain)
if __name__ == '__main__':
sys.exit(main())
--------------------------------------------------------------------------------
What does this buy you? First and foremost, it gets you more appropriate
signal handling on POSIX systems than you would otherwise get by default.
Plus, when an unexpected exception comes up, sclapp's main wrapper catches
it and prints a user-friendly message explaining that a bug has occured, and
that the user should send a bug report. There are a number of other small,
but helpful, pieces; see the documentation for sclapp's main() function for
more information.
Let's look at a slightly more complicated example. Suppose your program needs
to perform some cleanup action before terminating. With python's normal
signal handling, a SIGPIPE will prevent this from happening, and will result
in a traceback. With sclapp, we can easily deal with this:
--------------------------------------------------------------------------------
import sclapp, signal
def mymain(argv):
try:
sclapp.print_debug('calling do_something()...')
do_something()
finally:
sclapp.print_warning('cleaning up...')
cleanup()
sclapp.register_exit_signals([signal.SIGPIPE])
sclapp.set_error_output_level(sclapp.INFO)
main = sclapp.main(mymain)
if __name__ == '__main__':
sys.exit(main())
--------------------------------------------------------------------------------
Now, SIGPIPE will cause an ExitSignalException to be raised, and your cleanup
function will be called. This example also illustrates how easy it is to use
sclapp's prioritized error output to set the level of verbosity for error
messages. In this example, the first message will not be printed, because
it's priority (DEBUG) is less than the desired error output level (INFO). The
second message, however, will be printed, as it's priority is WARNING, which is
>= INFO. (The output level constants are integers defined in sclapp).
3. Core Functionality
3.1 Signal Handling
Programs utilizing sclapp's signal handling functionality can easily be made
to deal with signals in a graceful way, something that python does not do
without any effort.*
sclapp provides a simple interface for managing signal handling that maps
desired signals to python exceptions. Signals are considered to fall into
one of four categories:
exit signals: those that will cause the program to exit, after performing
some cleanup actions
notify signals: those that the program would like to know about, but may not
lead to termination
default signals: those that are set to SIG_DFL, which result in silent and
immediate termination on most UNIX-like systems
ignore signals: those that are set to SIG_IGN, which are completely ignored
(with certain exceptions imposed by the operating system)
Both exit and notify signals raise an exception when caught. The two are
handled slightly differently in that an exit signal always trumps a notify
signal in the case that both are raised nearly simultaneously, and exit signal
exceptions are caught by the main() wrapper, rather than surfacing to
produce tracebacks.
notify signals will raise a SignalError when caught; exit signals raise an
ExitSignalError. Your program probably shouldn't explicitly catch
ExitSignalError exceptions, but, rather, handle them with try...finally blocks.
The exception will, instead, be caught in sclapp's main() function wrapper, and
the program will exit appropriately from there.
The default signal handling settings are ideal for programs that wish to
silently terminate in response to normal exit signals, and don't need to
perform any clean up actions prior to termination. If your program is intended
to tidy up a bit before dying, you should use sclapp's signal registration
functions to ensure that the appropriate signals are handled as exit signals:
sclapp.register_exit_signals(sclapp.get_default_signals())
* The disadvantaged of python's default signal handling are especially
noticeable when using a python "filter" in a shell (on a UNIX-like system).
Given any python program that produces more than one line of output on stdout,
the following will result in a traceback (from an uncaught IOError):
python program.py | head -n1
Try it! sclapp-ified programs that do not disable sclapp signal handling will,
by default, not produce this traceback, as SIGPIPE is set to SIG_DFL (which
normally causes the program to terminate silently). Programs using sclapp
that need to perform cleanup actions before exiting should therefore explicitly
register SIGPIPE as an exit signal using register_exit_signals().
3.2 Protected Output
Situations may arise when stdout and/or stderr become unusable, and writing
to them raises an IOError. sclapp's output protection catches this
exception, and handles it appropriately. Namely, if sclapp is handling
SIGPIPE, the error is dropped, and, if necessary, the signal exception
resulting from SIGPIPE is forcibly raised, if it was interrupted by the
IOError. If sclapp is not handling SIGPIPE (or the program is running on a
non-POSIX system), the IOError is converted to a CriticalError, which is
caught in the main function (after any cleanup has occured), and reported
to the user. Consequently, these situations should never result in a
traceback.
sclapp achieves this output protection by replacing sys.stdout and sys.stderr
with alternative, limited file-like objects. Be aware of this if you are
also attempting to modify these objects (it is likely this will not work very
well).
Be advised that sclapp will not treat all IOError's as described above, only
those that are a) likely to occur as a result of permanent problems with the
respective file object and b) not likely to have been caused by a bug in the
calling program. (Currently, sclapp only deals with EPIPE errors, and passes
all others along to the caller).
3.3 Prioritized Error Output
In addition to more critical functionality, sclapp also provides a number of
functions for generating output on stderr. These functions allow each
message that is printed to be given a priority. Your program specifies a
minimum priority for messages that you would like to be printed, allowing
you to easily adjust the verbosity of error reporting.
sclapp provides this functionality by thinly wrapping bound methods of a
Logger object, which is provided by the logging module, part of the standard
python library. As is described by that module's documentation, sclapp
provides several convenient constants for specifying the output level that
you desire. Namely, the following constants are defined:
DEBUG, INFO, WARNING, ERROR, CRITICAL
See the rest of the module documentation for further information on using
the prioritized error output functionality provided by sclapp.
4. Miscellaneous Optional Functionality
sclapp provides some "bonus" convenience functionality if your program needs
it.
4.1 Daemonization
sclapp will daemonize your program if given the appropriate argument to the
main() wrapper.
4.2 Transparent Help & Version Options
4.3 User Friendly Bug Handling
sclapp will, by default, handle uncaught exceptions (except for CriticalErrors,
ExitSignalErrors, and some IOErrors, as described above) by telling the user
that a bug has been encountered, and asking him to file a bug report. The
exact message can be changed (see the documentation for the main() wrapper).
| Package Contents | ||||||
| ||||||
| Classes | ||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||
| Functions | ||
| ||
| Data | ||
| CRITICAL = 50 DEBUG = 10 ERROR = 40 INFO = 20 WARNING = 30 __version__ = '0.2.3' | ||