views:

101

answers:

3

Python optparse works very good when script usage is something like this

%prog [options] [args]

But I need to write help for script with 1 required argument, so usage will be like this

%prog action [options] [args]

You can see something similar when you use Subversion - its usage string is

svn <subcommand> [options] [args]

So my question is: is it possible to prepare help for required argument with optparse in the manner of Subversion? As a result I want to see help like this:

Usage: python myscript.py action [options] [args]

Available actions:
  foo
  bar

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -v, --verbose         Verbose mode. Output debug log to stdout.
+2  A: 

Yes. You can set the usage string like this:

usage = "%prog action [options] [args]"
parser = OptionParser(usage=usage)
parser.add_option("-v", "--verbose",
                  action="store_true", dest="verbose", default=True,
                  help="make lots of noise [default]")

Prints the following:

Usage:  action [options] [args]

Options:
  -h, --help     show this help message and exit
  -v, --verbose  make lots of noise [default]

This was copied almost verbatim from the docs.

Edit:

Based on your comment you could use the description to achieve something similar, though you can't put new-line characters in it.

parser.description = 'Available actions: foo, bar'

Will look like this:

Usage:  action [options] [args]

Available actions: foo, bar

Options:
  -h, --help     show this help message and exit
  -v, --verbose  make lots of noise [default]
tgray
I know that I can set any usage string. My question is about preparing help for arguments. For options I can use something likeparser.add_option('-v', '--verbose', action='store_true', dest='VERBOSE', default=False, help='Verbose mode. Output debug log to stdout.')And I'll get pretty formatted help for -v option. But I want to add information about argument usage as well. For now I can see the only way is to use option instead of argument, so I will have to write python myscript.py -a foo [...] instead of python myscript.py foo [...]
krig
+8  A: 

I think a good solution for you is argparse, which has been proposed for inclusion in Python 2.7 and 3.2. It handles subcommands, I believe as you want, and the linked page includes a link to a page on porting your code from optparse.

See also the question command-line-arguments-in-python, into which someone edited a list of references that appears to include exactly the same thing you want:

Peter Hansen
Yes, looks like argparse is what I need.Thanks.
krig
A: 

I've run into this problem as well. My solution was to declare commands in a list or tuple, format them into the usage parameter of OptionParser and then use the args list provided by the parser to determine if a command was provided or not, since it technically has to be args[0]. Eg:

self.commands = ('foo', 'bar' ...)
self.parser = <initialized instance of OptionParser>
(self.options, self.args) = parser.parse_args()

if len(self.args) == 0:
   self.parser.error("Command required")

self.command = self.args[0]
if not self.command in self.commands:
   self.parser.error("Command not recognized")

#... etc

This kinda gets you a command system that looks like Subversion's, but admittedly optparse could be better. I've heard the argparse module is supposed to make it into the stdlib, but with 2.7 being the last of the 2 series releases, I guess you'd have to wait for it to be incorporated into 3.x. Of course you can just install argparse, but that's a drag in some cases.

kprobst
Reading and validating arguments is not a problem - I already implemented this with dictionary instead of tuple (key is action and value is action description). The problem is help preparation.
krig