[Tutor] Making a better main() : Critique request

Tony Cappellini cappy2112 at gmail.com
Mon Aug 21 01:54:42 CEST 2006


Some time ago, I had read an article on Guido's blog (I think) about ways to
improve the main() function
in a Python script. There were many replies, and I thought I would try to
implement some of these ideas.


I had found that in every python program I wrote I would

1. check the number of arguments as well as checking that each argument was
valid.
2. Provide an option for the user to display how long the program took to
run, for those programs which
    processed a lot of files.
3  If any input files were used, I would also check to make sure they
existed.
    Recently, I've implemented a browser dialogue from Jimmy Retzlaff's
EasyDialogs to make it easy to locate
    files outside of the current directory.
4. If the argument validation failed, a Usage() function would be called to
show all possible arguments
5. Provide a "help" option  to display all the possible arguments.


I could see that I was writing enough lines of code that main() was getting
cluttered, and not easy
to see what was happening at a glance. Sure, I could move all of this
outside of main(), but some function had to
initiate all of the processing. So, I've decided to put all of this
processing into a class.

I had thought about putting this class in a separate file, so the file
containing main() would only have a few imports, one line to instantiate the
class to validate the cmd line args, and one function call to actually
"start" the meat of the program, if all input args were valid.

I didn't like the idea of having to start with 2 files for every program. So
now the class definition for the input processing is in the main file, and
this file is now full of code, but at least main() is short & sweet.

Since I'm just getting back into using Python again, I would appreciate some
constructive comments on this processing, and if this version of "a better
main()" is really better or not.


So Now I'm trying to use more exception handling in the validating of the
input arguments, and have defined a few of my own exceptionclasses.

However, I'm getting the cart before the horse, and can't see the forest
through the trees.

I don't like the idea of defining classes within classes, but I'm havign a
problem geting the ProgramStartup class to
see the ArgumentError exception class.


Am Ion the right track to makign a better main by moving all the argument
validation to a class, or should I levae it to discrete functions in the
main file?

thanks

# system imports
from os import getcwd
import string
import sys
import types
import time
import getopt
from EasyDialogs import AskFileForOpen
from os.path import exists
from exceptions import Exception
# system imports

# user-defined imports
import tcpy
from tcpy import pause
from tcpy import cls


# user-defined imports

#/////////////////////////////////////////////////////////
# USER-DEFINED EXCEPTIONS

class UserExceptions(Exception):
    def __init__(self, args=None):
        self.args = args

class ArgumentError(UserExceptions):
    def __init__(self):
        #UserExceptions.__init__(self, args)
        #self.args = args
        pass


class ProgramExitError(UserExceptions):
    def __init__(self, args):
        UserExceptions.__init__(self, args)
        self.args = args


#/////////////////////////////////////////////////////////
# CLASS DEFINITIONS
#/////////////////////////////////////////////////////////

class ProgramStartup(object):
    "this class will handle all the details of checking/validating the
program arguments"

    def __init__(self, ProgramArgs):
        self.MinArgs = 1
        self.MaxArgs = 2 #input filename
        self.ShowTimer = False
        self.StartTime = 0
        self.EndTime = 0
        self.InputFilename = ""

        self.ProgramName = ""
        self.ProgramVersion = "0.1"
        self.BAD_ARG = True

        self.ArgsDict ={'-t':"Show program execution time",
                        '-v':"Show program version number",
                        '-b':"Browse for input file",
                        '-f <filename>':"File to be processed",
                        '-h':"Show this help screen"
        }

        self.ValidArgs ='tvbf:'


        try:
            self.ValidateArgs(ProgramArgs)
        except getopt.GetoptError, ArgumentError:
            self.Usage()

    def Usage(self):

        print"\nSyntax is: ",
        print"%s " % ProgramName,
        for key in self.ArgsDict.iterkeys():
            print"%s " % key,

        print"\n\nWhere"
        for key, item in self.ArgsDict.iteritems():
            print"\n%s=%s" %(key, item)
        print
        sys.exit()

    def ShowExecTime(self):

        if self.ShowTimer:
            print"\nTotal time = %6.2f seconds" % (
self.EndTime-self.StartTime)

        return None

    def ShowTitle(self):

        print"\n\n%s Version %s \n\n" %(self.ProgramName,
self.ProgramVersion)
        return None

    def ValidateArgs(self, args):
        global AskFileForOpen, getcwd, ArgumentError

        ArgValidationStatus = 0
        self.InputFilename = None

        ProgramDir = getcwd()

        if len(args) < self.MinArgs:
            raise ArgumentError

        try:
            (Opts, Args) = getopt.getopt(args, self.ValidArgs )
            for opt, arg, in Opts:
                if opt == '-v' :
                    print"\n%s ver %s " % (self.ProgramName,
self.ProgramVersion)
                    sys.exit()
                elif opt == '-t' :
                    ShowTimer = True
                elif opt == '-f':
                    if exists(Filename) != True:
                        print"\nFile %s does not exist, or could not be
opened for reading" % Filearg
                        pause()
                elif opt == '-b':
                    self.InputFilename =
AskFileForOpen(defaultLocation=ProgramDir, message="Select Phonebook to be
processed", windowTitle="File Open")
        except getopt.GetoptError:
            raise



    def StartProgram(self):

        self.ShowTitle()

        if self.InputFilename:
            self.StartTime = time.time()

           # CALL THE ACTUAL MEAT OF THE PROGRAM HERE

            self.EndTime=time.time()
            self.ShowExecTime()
        else:
            print"\nNo input filename was given.\n"

        return None


#/////////////////////////////////////////////////////////

def main(args):

    #try:
    program=ProgramStartup(args[1:])
    #except ArgumentError: # user-defined exception
    #raise # we need to return to main here

    program.StartProgram() # pass all arguments after the word Python

    return None

#/////////////////////////////////////////////////////////
# run the program
if __name__ == '__main__':
    cls()
    main(sys.argv)
    print"\n\n%sThe program has ended\n" % (' ' * 40)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/tutor/attachments/20060820/06274aad/attachment-0001.html 


More information about the Tutor mailing list