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
       
version

 
Classes
       
exceptions.Exception
Error
CriticalError
ExitSignalError
UsageError
SignalError

 
class CriticalError(Error)
    indicates a fatal error (can and should be raised by sclapp caller)
 
 
Method resolution order:
CriticalError
Error
exceptions.Exception

Methods defined here:
__init__(self, code, message)
__str__(self)

Data and other attributes inherited from Error:
code = 0

Methods inherited from exceptions.Exception:
__getitem__(...)

 
class Error(exceptions.Exception)
    base exception for other exceptions defined in this module
 
  Data and other attributes defined here:
code = 0

Methods inherited from exceptions.Exception:
__getitem__(...)
__init__(...)
__str__(...)

 
class ExitSignalError(CriticalError)
    indicates that an exit signal has been caught (raised by sclapp)
 
 
Method resolution order:
ExitSignalError
CriticalError
Error
exceptions.Exception

Methods defined here:
__init__(self, signum)
__str__(self)

Data and other attributes inherited from Error:
code = 0

Methods inherited from exceptions.Exception:
__getitem__(...)

 
class SignalError(Error)
    indicates that a notify signal has been caught (raised by sclapp)
 
 
Method resolution order:
SignalError
Error
exceptions.Exception

Methods defined here:
__init__(self, signum)
__str__(self)

Data and other attributes inherited from Error:
code = 0

Methods inherited from exceptions.Exception:
__getitem__(...)

 
class UsageError(CriticalError)
    indicates a usage error (can and should be raised by sclapp caller)
 
 
Method resolution order:
UsageError
CriticalError
Error
exceptions.Exception

Methods defined here:
__init__(self, message=None)
__str__(self)

Data and other attributes inherited from Error:
code = 0

Methods inherited from exceptions.Exception:
__getitem__(...)

 
Functions
       
debug()
disable_announce_signals()
disable_announce_signals() -> None
 
Normally, sclapp's signal handler's will print a warning message
indicating that a signal has been caught.  Calling this function
disables this behavior.
disable_signal_handling()
disable_signal_handling() -> None
 
Disables sclapp signal handling.
enable_announce_signals()
enable_announce_signals() -> None
 
Normally, sclapp's signal handler's will print a warning message
indicating that a signal has been caught.  If this functionality has
been disabled, calling this function will re-enable this behavior.
enable_signal_handling()
enable_signal_handling() -> None
 
Enables sclapp signal handling.
get_all_signals()
get_all_signals() -> list
 
Returns a list containing all signal numbers.
get_caught_signals()
get_caught_signals() -> list
 
Returns a list containing all signal numbers that have been caught by
sclapp signal handlers.
get_default_signals()
get_default_signals() -> list
 
Returns a list containing all signal numbers that are currently being
handled by sclapp as default signals (SIG_DFL).
get_exit_signals()
get_exit_signals() -> list
 
Returns a list containing all signal numbers that are currently being
handled by sclapp as exit signals.
get_ignore_signals()
get_ignore_signals() -> list
 
Returns a list containing all signal numbers that are currently being
handled by sclapp as ignore signals (SIG_IGN).
get_notify_signals()
get_notify_signals() -> list
 
Returns a list containing all signal numbers that are currently being
handled by sclapp as notify signals.
ignore_all_signals()
ignore_all_signals() -> None
 
Causes all signals to be ignored.
main(realmain, name=None, author='the author', version=None, doc=None, handle_signals=True, protect_output=True, daemonize=False, bug_message='${traceback}\nSomething bad happened, and is most...thor}.\nInclude the error message(s) printed here.', version_message='${name} version ${version}', ignore_unrecognized_options=True)
main(self, realmain, name = _DEFAULT_NAME,
  author = _DEFAULT_AUTHOR, version = _DEFAULT_VERSION,
  doc = _DEFAULT_DOC, handle_signals = _DEFAULT_HANDLE_SIGNALS,
  daemonize = _DEFAULT_DAEMONIZE, bug_message = _DEFAULT_BUG_MESSAGE,
  version_message = _DEFAULT_VERSION_MESSAGE,
  ignore_unrecognized_options = _DEFAULT_IGNORE_UNRECOGNIZED_OPTIONS
) -> function
 
realmain (function): the main() function to wrap
 
The following optional parameters affect behavior of the wrapper
main() function.  The full consequences of specifying non-default
values for these parameters are explained more thoroughly below.
 
name (string): the program
author (string): the program's author
version (string): version string for the program
doc (string): documentation for the program
handle_signals (boolean): enables sclapp signal handling on UNIX
  systems if True
daemonize (boolean): program will daemonize on UNIX systems if True
bug_message: message to print if an uncaught exception is raised in
  realmain
version_message: message to print when users request the program's
  version
ignore_unrecognized_options: if True, options other than -h/--help
  and -v/--version will cause no error; if False, a UsageError will
  be raised
 
Some of the optional parameters mentioned above cause sclapp to
parse argv and respond appropriately:
 
* If version_message is not None, sclapp will respond to the -v command
  line switch by printing the version_message to stdout.
* If doc is not None, sclapp will respond to the -h command line switch
  by printing doc to stdout.
 
Both bug_message and version_message are parsed for substitution
strings prior to printing.  Specifically, sclapp uses the Template
class of the standard library's string module to make the following
substitutions:
 
${name} is replaced by the name parameter
${author} is replaced by the author parameter
${version} is replaced by the version parameter
${doc} is replaced by the doc parameters
 
The doc parameter is parsed for all other substitutions before it is
itself substituted.  Thus, callers should feel free to add ${name},
${author}, and ${version} to the doc parameter, and they will be
replaced appropriately before printing.
 
Be default, sclapp installs signal handlers that are easily
configurable using module functions.  Setting handle_signals to
False will disable this behavior.
 
sclapp can also be used to write simple daemons.  To cause the
program to daemonize before launching the wrapped main() function,
set daemonize to True.
 
bug_message, if not None, will be printed in the event that an
unhandled exception is caught by the main wrapper.  The default
message simply informs the user that a likely bug has been
encountered, and asks them to file a bug report to the author.
 
If ignore_unrecognized_options is False, sclapp will complain about
options it isn't expecting.  If your program does not explicitly
handle command line options, you probably want this.  Otherwise, you
definately don't want this, as any of your options will cause a
UsageError to be reported before you have a chance to handle them.
 
If sclapp finds that it can't do anything useful with -h/--help or
-v/--version (if version, doc are None, or contain substitutions
sclapp can't fulfill), sclapp does nothing with command line options.
 
The new main() function will return the wrapped function's return
value, unless an exception is raised (including exceptions resulting
from an exit signal being received), in which case the return value
is an integer intended to act as the program's termination status.
print_critical(message)
print_critical(message) -> None
 
Prints a message to stderr with priority CRITICAL.
print_debug(message)
print_debug(message) -> None
 
Prints a message to stderr with priority DEBUG.
print_error(message)
print_error(message) -> None
 
Prints a message to stderr with priority ERROR.
print_info(message)
print_info(message) -> None
 
Prints a message to stderr with priority INFO.
print_warning(message)
print_warning(message) -> None
 
Prints a message to stderr with priority WARNING.
register_default_signals(signums)
register_default_signals(signums) -> None
 
signums: a list of signal numbers desired to be treated as default
         signals (SIG_DFL)
 
Causes all signal numbers in signums to be handled by sclapp as default
signals (SIG_DFL).
register_exit_signals(signums)
register_exit_signals(signums) -> None
 
signums: a list of signal numbers desired to be treated as exit signals
 
Causes all signal numbers in signums to be handled by sclapp as exit
signals.
register_ignore_signals(signums)
register_ignore_signals(signums) -> None
 
signums: a list of signal numbers desired to be treated as ignore
         signals (SIG_IGN)
 
Causes all signal numbers in signums to be handled by sclapp as ignore
signals (SIG_IGN).
register_notify_signals(signums)
register_notify_signals(signums) -> None
 
signums: a list of signal numbers desired to be treated as notify
         signals
 
Causes all signal numbers in signums to be handled by sclapp as notify
signals.
set_error_output_level(level)
set_error_output_level(level) -> None
 
level: int minimum priority of error messages that are displayed
 
Sets the minimum priority required for an error output message to actually
be seen.  sclapp defines the following constants for convenience:
 
DEBUG = 10
INFO = 20
WARNING = 30
ERROR = 40
CRITICAL = 50
 
Observant programmers will recognize these as the same constants defined
by the logging module, which provides the underlying functionality for
sclapp's prioritized error output.

 
Data
        CRITICAL = 50
DEBUG = 10
ERROR = 40
INFO = 20
WARNING = 30
__version__ = '0.2.3'