I am in the process of writing a small(er) Python script to automate a semi-frequent, long, and error-prone task. This script is responsible for making various system calls - either though os.system or through os.(mkdir|chdir|etc).
Here is an example of my code right now:
class AClass:
def __init__(self, foo, bar, verbose=False, silent=False):
# Sets up variables needed for each instance, etc
self.redirect = ''
if silent:
self.redirect = '> 2>&1'
self.verbose = verbose
def a_method(self):
""" Responsible for running 4-6 things via system calls as described """
if self.verbose and not self.silent:
print "Creating a directory"
try:
os.mkdir('foobar')
except OSError, e:
raise OSError, "Problem creating directory %s: %s" % (e.filename, e.strerror)
if self.verbose and not self.silent:
print "Listing a directory"
if (os.system('ls foobar %s') % self.redirect) is not 0:
raise OSError, "Could not list directory foobar"
def b_method(self):
""" Looks very similar to a_method() """
def run(self):
""" Stitches everything together """
try:
a_method()
except OSError, e:
print "a_method(): %s" % e.strerror
sys.exit(-1)
try:
b_method()
except OSError, e:
print "b_method(): %s" % e.strerror
sys.exit(-1)
Obviously writing all the if self.verbose and not self.silent
is messy and then the try/catch
or if
around each call is ugly to look at.
I would have liked to use Python's logging class and simply have one logging level (verbose) configurable via command line and then I can simple call logger.debug('My message')
but I am using Python 2.2 and I do not have access to the logging
class.
Summary/Base Questions
I am using Python 2.2 and I cannot change this. I am running on an ESX 3.0.2 server and I cannot touch it in any other way for the time being.
What is the best way to handle error checking and verbose output without tying this logic to your class (which should only do One Thing)?
How can I reduce the clutter with something more simple or elegant to look at?
Thanks!
So, instead, assign sys.stdout to a dummy class whose write is a no-op if you need to be unverbose or silent, then just use print without needing guards. (Do remember to restore sys.stdout to the real thing for prints that aren't so conditioned -- easier to encapsulate in a couple of functions, actually).
For error checks, all the blocks like:
can and should be like
for what I hope is a pretty obvious
def docall(acallable):
.Similarly, other try/except case and ones where the new exception is raised conditionally can become calls to functions with appropriate arguments (including callables, i.e. higher order functions). I'll be glad to add detailed code if you clarify what parts of this are hard or unclear to you!
Python 2.2, while now very old, was a great language in its way, and it's just as feasible to use it neatly, as you wish, as it would be for other great old languages, like, say, MacLisp;-).