views:

45

answers:

2

HI, guys.

I am using cmd and optparse to develop a CLI.py for a collection of already-functional classes (CDContainer, CD, etc.). The following are some parts of the code. I have a problem here. when there are exceptions(wrong input type or missing values), the optparse will exit the whole program instead of the specific command method.

import cmd
class CLI(cmd.Cmd):

    def do_addcd(self, line):
        args=line.split()
        parser = OptionParser()
        parser.add_option("-t", "--track", dest="track_number", type="int",
            help="track number")
        parser.add_option("-n", "--cdname", dest="cd_name", type="string",
            help="CD name")
        (options, positional_args) = parser.parse_args(args[0:])
        cd_obj= CD()
        cd_obj.addCD(options.track_number, options.cd_name)

Under ">python", if I type CLI.py, then I will have (Cmd), so I could type command like "(Cmd)addcd -t 3 -n thriller". but if I type "addcd -t r -n 3", then optparse will terminate the whole CLI.py and exit. This is not good for me. I want to remind the user for each method, instead of terminating the whole program.

however, the optparse documentation says "the whole program exits". so I could not use optparse "blindly". what can I do?

A: 

It probably has to do with the types that you're passing to the CD class: without seeing it, there's a really good chance that it's failing there. Before creating that object and passing the arguments, it's a really good idea to clean that data, ensure it's the correct type, and perform any other checks that you see as being reasonable.

Andrew Sledge
+4  A: 

The optparse documentation says this:

If optparse‘s default error-handling behaviour does not suit your needs, you’ll need to subclass OptionParser and override its exit() and/or error() methods.

Ideally you'd define a new type of exception, subclass optparse, raise the exception in the exit() or error() method that you've overridden, and then catch it and deal with it as needed.

You can cheat, though. If you want the error message printed but just don't want the program to exit, then you can catch the SystemExit exception to catch where optparse is trying to exit and stop it.

So, for example:

try:    
    (options, positional_args) = parser.parse_args(args[0:])
except SystemExit:
    return

cd_obj= CD()
cd_obj.addCD(options.track_number, options.cd_name)

or to override the method:

import optparse

class OptionParsingError(RuntimeError):
    def __init__(self, msg):
        self.msg = msg

class OptionParsingExit(Exception):
    def __init__(self, status, msg):
        self.msg = msg
        self.status = status

class ModifiedOptionParser(optparse.OptionParser):
    def error(self, msg):
        raise OptionParsingError(msg)

    def exit(self, status=0, msg=None):
        raise OptionParsingExit(status, msg)

and then:

try:
    parser = ModifiedOptionParser()
    parser.add_option("-t", "--track", dest="track_number", type="int",
        help="track number")
    (options, positional_args) = parser.parse_args(args[0:])
except OptionParsingError, e:
    print 'There was a parsing error: %s' % e.msg
    return
except OptionParsingExit, e:
    print 'The option parser exited with message %s and result code %s' % (e.msg, e.status)
    return

cd_obj= CD()
cd_obj.addCD(options.track_number, options.cd_name)
Robie Basak
I see. what about I do not use the optparse? I parse the args by myself and analyze it accordingly. if I use optparse, as you said, I should overwrite its exit or error methods somehow, which I am not that confident that i could do it.
pepero
I would stick with optparse. It will keep option parsing behaviour consistent, and it would be a lot of work to write an argument parser that follows normal conventions.I've updated my answer with an example of overriding the error method.
Robie Basak
hi, Robie, thank you so much for your detailed answer with code!!! it works with my intention! but just one thing, when I call method -help, e.g., addcd -h, it lists the options, and then exit the program. is it also possible to solve it for "help". Thanks a lot!
pepero
@pepero try my newest edit.
Robie Basak
thank you Robie, it works!!
pepero
Hi, Robie, there is one thing, if you type randomly after the command without "-",e.g. "addcd rffdsa", then the optparse could not identifiy any misinputs and also the program crashes. Is it possible to catch this kind of error and return. thanks in advance!
pepero