July 02, 2009

Python Skeleton Code: base.py

I have a snippet of code I use whenever I start a new python commandline tool. Today, I read a post that added the use of the logging module to their skeleton code. I didn't realize how simple that module was. For some reason, I got bamboozled into thinking it was more complicated by earlier examples. So, I really appreciated that post. Then I thought I should put my skeleton out there for others to use if they want. My tiny addition is to add a configuration file. Optionally, you can create a config file based on the ConfigParser module to store default values for your tool in case you end up needing lots of commandline options. I'm sure this will continue to evolve, but here it is as of today.
#!/usr/bin/env python                                                                             
"""
base.py - a skeleton starting-point for python scripts by Roger Allen.
"""
import os
import sys
import logging
import ConfigParser
from optparse import OptionParser

# ======================================================================
# XXX extend this run function XXX
def run(options, args):
"""options is a dictionary of your commandline options, args is a list of the remaining commandline arguments
"""
# -v to see info messages
logging.info("Options: %s, Args: %s" % (options, args))
# -v -v to see debug messages
logging.debug("Debug Message")
# we'll always see these
logging.warn("Warning Message")
logging.error("Error Message")
print "Hello, World"
return 0

# ======================================================================
# XXX add your commandline arguments XXX
def parse_args(argv):
"""parse commandline arguments, but use config files to override
default values specified in the add_option calls
"""
config = Config()
parser = OptionParser()
parser.add_option("-v","--verbose",
action="store_true",dest="verbose",action='count',
default=config.get("options","verbose",0), # config file has verbosity level
help="Increase verbosity (specify multiple times for more)")
# XXX add more options here XXX
(options, args) = parser.parse_args(argv)
# adjust logging level based on verbosity flag
log_level = logging.WARNING # default
if options.verbose == 1:
log_level = logging.INFO
elif options.verbose >= 2:
log_level = logging.DEBUG
logging.basicConfig(level=log_level)
return (options, args)

# ======================================================================
# Should not have to edit below this line
class Config():
"""Read the <program_name>.cfg or ~/.<program_name>.cfg file for configuration options.
Handles booleans, integers and strings
"""
def __init__(self):
self.config = ConfigParser.ConfigParser()
program_name = os.path.basename(sys.argv[0].replace('.py',''))
self.config.read([program_name+'.cfg', os.path.expanduser('~/.'+program_name+'.cfg')])
def get(self,section,name,default):
"""in the config file, try to find the 'name' in the proper 'section'.
if not found, return the passed default value."""
try:
if type(default) == type(bool()):
return self.config.getboolean(section,name)
elif type(default) == type(int()):
return self.config.getint(section,name)
else:
return self.config.get(section,name)
except:
return default

def main(argv):
"""The main routine, taking in a commandline argv string sans the program name.
"""
options, args = parse_args(argv)
return run(options, args)

if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))