views:

74

answers:

3

my python version is 2.4.3.

Now I am developing a CLI with cmd module from python for a CD player. I have some classes like CDContainer (with method like addCD, removeCD, etc), CD (with method like play, stop, pause). Now, I want to add some options for the commands and also if the options inputs are not correct, the CLI could return proper information about either wrong input type or wrong values. e.g., I want to have "addcd --track 3 --cdname thriller". what I am doing now is to get all the arguments via , split it, and assign it to the relevant variables, as follows.

my question is in python, is there some module that is handy for my case to parse and analyse the options or arguments ?

REVISION: OK, I edit it, thanks to gclj5 comments.

import cmd
class CDContainerCLI(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)
        cd_obj= CD()
        cd_obj.addCD(options.track_number, options.cd_name)

If possible, could you write some code samples, just to show how to do it?

Thank you very much!!

+3  A: 

my question is in python, is there some module that is handy for my case to parse and analyse the options or arguments ?

Yes, the argparse module.

If you're already familiar with the getopt library from C, that's also available as a python module - though less easy to use, if you're not already used to it.

sepp2k
+3  A: 

Depending on your Python version, you should take a look at either optparse (since version 2.3, deprecated since version 2.7) or argparse (since version 2.7).

Some sample code using optparse (line is the string you read from stdin in your CLI):

from optparse import OptionParser

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")

# args[0] contains the actual command ("addcd" in this example).
(options, positional_args) = add_cd_parser.parse_args(args[1:])

if options.track_number != None and options.cd_name != None:
    cd_obj= CD()
    cd_obj.addCD(options.track_number, options.cd_name)
    print "add CD (track %d, name %s)" % (options.track_number, options.cd_name)

This parser only handles your "addcd" command. For more commands you could use several OptionParser objects in a dictionary with the command name as the key, for instance. You could parse the options like this then:

(options, args) = parsers[args[0]].parse_args(args[1:])

Take a look at the documentation for optparse for more information. It's very easy to output usage information, for instance. There is also a tutorial available.

gclj5
hi, gclj5, thank you for your answer. i am using 2.4.3. I heard about this optparse, but I do not know how to use it with my code. e.g. how could I integrate it into the addcd function? where and how should I add it?
pepero
I don't know about the exact structure of you program, so I can't tell you exactly where to add it. But I added some sample code to illustrate the usage of the optparse package. The general idea would be to let the CLI parsing code call the corresponding functions with the parsed options.
gclj5
Hi, gclj5, thank you so much for your code. it is args[0:], not args[1:], because, the args are taken as the input for the method. I revise the code from my original post. but there is still some problem. when there is some exceptions(wrong type or missing option), this optionparse will exit for the whole program, instead of exit just for the relevant method. how could we solve this?
pepero
Just catch the exceptions and handle the errors on your own (informing the user and exiting the method). Also see the section [How optparse handles errors](http://docs.python.org/library/optparse.html#how-optparse-handles-errors) in the optparse tutorial. BTW, you might as well use `args` directly (without `[0:]`) in your case.
gclj5
hi, gclj5, so if I catch the exception and handle errors by myself, then the optparse will not be needed at all. is that right? this is a bit disappointing, just so close to have something handy, but at the end, I still could not use it.
pepero
Well, it still does all the parsing for you. It handles different ordering of the arguments etc. But granted, optparse is mainly intended to handle command line parameters given to your script from the shell. As far as I understand, you have a command line interface *within* your application. I still think a package like optparse can save you some work. I don't really know how the cmd package works, but perhaps you could catch those exceptions in a central place, print an error message and then carry on handling the command line.
gclj5
+1  A: 

Here's a demo script I wrote a few months ago when my co-workers and I were learning the argparse module. It illustrates several of the module's behaviors and features:

import sys
import argparse

def parse_command_line():
    # Define our argument parser.
    ap = argparse.ArgumentParser(
        description = 'This is a demo app for the argparse module.',
        epilog      = 'This text will appear after options.',
        usage       = '%(prog)s [options]',  # Auto-generated by default.
        add_help    = False,                 # Default is True.
    )

    # A grouping of options in the help text.
    gr = ap.add_argument_group('Required arguments')

    # A positional argument. This is indicated by the absense
    # of leading minus signs.
    gr.add_argument(
        'task',
        choices = ['get', 'put'],
        help = 'Task to be performed.', # Help text about an option.
        metavar = 'TASK', # Placeholder to be used in an option's help text.
                          # The default in this case would be "{get,put}".
    )

    # Another group.
    gr = ap.add_argument_group('Common options')

    # A basic option.
    gr.add_argument(
        '-s', '--subtask',
        action = 'store',  # This is the default.
                           # One value will be stored, as a string, 
                           # in opt.subtask
    )

    # A required option, with type conversion.
    gr.add_argument(
        '-u', '--user',
        required = True, # Options can be made mandatory.
                         # However, positional arguments can't be made optional.
        type = int,      # Convert opt.user to an integer.
                         # By default, it would be a string.
    )

    # A flag option.
    gr.add_argument(
        '--overwrite',
        dest = 'clobber',      # Store in opt.clobber rather than opt.overwrite.
        action = 'store_true', # If option is supplied, opt.clobber == True.
    )

    # Another group.
    gr = ap.add_argument_group('Some other options')

    # An option with multiple values.
    gr.add_argument(
        '--datasets',
        metavar = 'DATASET', # Default would be DATASETS.
        nargs = '+',  # If option is used, it takes 1 or more arguments.
                      # Will be stored as a list in opt.datasets.
        help = "The datasets to use for frobnication.",
    )

    # An option with a specific N of values.
    gr.add_argument(
        '--bar',
        nargs = 1,    # Takes exactly one argument. Differs from a basic
                      # option because opt.bar will be a list rather 
                      # than a string.
        default = [], # Default would be None.
    )

    # A file option.
    gr.add_argument(
        '--log',
        type    = argparse.FileType('w'),  # Will open a file for writing.
        default = sys.stdout,
        help    = 'Log file (default: STDOUT)',
    )

    # Another group.
    gr = ap.add_argument_group('Program information')

    # A version option.
    gr.add_argument(
        '-v', '--version',
        action = 'version', # Will display version text and exit.
        version = 'argparse_demo v1.2.0', # The version text.
    )

    # A help option.
    gr.add_argument(
        '-h', '--help',
        action = 'help', # Will display help text and exit.
    )

    # Parse the options.
    # If given no arguments, parse_args() works with sys.argv[1:].
    # And the object it returns will be of type Namespace.
    opt = ap.parse_args()

    return opt

command_lines = [
    'argparse_demo.py put -u 1',
    'argparse_demo.py get -u 234 --over --data a b c --bar XYZ -s munch --log _log.txt',
    'argparse_demo.py -h', # Will exit() here.
]

for c in command_lines:
    sys.argv = c.split()
    opt = parse_command_line()
    print opt
FM