How do I format positional argument help using Python's optparse?

10,298

Solution 1

The best bet would be to write a patch to the optparse module. In the meantime, you can accomplish this with a slightly modified OptionParser class. This isn't perfect, but it'll get what you want done.

#!/usr/bin/env python
from optparse import OptionParser, Option, IndentedHelpFormatter

class PosOptionParser(OptionParser):
    def format_help(self, formatter=None):
        class Positional(object):
            def __init__(self, args):
                self.option_groups = []
                self.option_list = args

        positional = Positional(self.positional)
        formatter = IndentedHelpFormatter()
        formatter.store_option_strings(positional)
        output = ['\n', formatter.format_heading("Positional Arguments")]
        formatter.indent()
        pos_help = [formatter.format_option(opt) for opt in self.positional]
        pos_help = [line.replace('--','') for line in pos_help]
        output += pos_help
        return OptionParser.format_help(self, formatter) + ''.join(output)

    def add_positional_argument(self, option):
        try:
            args = self.positional
        except AttributeError:
            args = []
        args.append(option)
        self.positional = args

    def set_out(self, out):
        self.out = out
def main():
    usage = "usage: %prog [options] bar baz"
    parser = PosOptionParser(usage)
    parser.add_option('-f', '--foo', dest='foo',
                      help='Enable foo')
    parser.add_positional_argument(Option('--bar', action='store_true',
                                   help='The bar positional argument'))
    parser.add_positional_argument(Option('--baz', action='store_true',
                                   help='The baz positional argument'))
    (options, args) = parser.parse_args()
    if len(args) != 2:
        parser.error("incorrect number of arguments")
    pass

if __name__ == '__main__':
    main()

And the output you get from running this:

Usage: test.py [options] bar baz

  Options:
    -h, --help         show this help message and exit
    -f FOO, --foo=FOO  Enable foo

Positional Arguments:
  bar  The bar positional argument
  baz  The baz positional argument

Solution 2

Try taking a look at argparse. Documentation says it supports position arguments and nicer looking help messages.

Solution 3

I'd be interested in a clean solution to this; I wasn't able to come up with one. The OptionParser really focuses entirely on the options; it doesn't give you anything to work with position args, as far as I've been able to find.

What I did was to generate a list of little documentation blocks for each of my positional arguments, using \ts to get the right spacing. Then I joined them with newlines, and appended that to the 'usage' string that gets passed to the OptionParser.

It looks fine, but it feels silly, and of course that documentation ends up appearing above the list of options. I haven't found any way around that, or how to do any complex stuff, i.e. a given set of options is described beneath the description for a positional arg, because they only apply to that arg.

I looked at monkey-patching OptionParser's methods and I remember (this was a year or so ago) that it wouldn't have been that difficult, but I didn't want to go down that path.

Share:
10,298

Related videos on Youtube

cdleary
Author by

cdleary

Updated on April 15, 2022

Comments

  • cdleary
    cdleary over 1 year

    As mentioned in the docs the optparse.OptionParser uses an IndentedHelpFormatter to output the formatted option help, for which which I found some API documentation.

    I want to display a similarly formatted help text for the required, positional arguments in the usage text. Is there an adapter or a simple usage pattern that can be used for similar positional argument formatting?

    Clarification

    Preferably only using the stdlib. Optparse does great except for this one formatting nuance, which I feel like we should be able to fix without importing whole other packages. :-)

  • cdleary
    cdleary over 14 years
    You can't specify help for positional arguments, unless I'm missing something major here. I want it to look just like the generated "Options" section. I think formatting it by hand is silly, so I'd probably write something to do it for me if it doesn't already exist.
  • cdleary
    cdleary over 14 years
    Yeah, I'm okay with the ordering, but my usage text gives names to the positional arguments and I want the name-explanation pairs to look the same in both the Arguments and Options sections.
  • cdleary
    cdleary over 14 years
    Thanks for the pointer, but I'd prefer to go stdlib if possible. This doesn't seem like such a difficult problem to solve that I should download and bundle a whole other options package to do it.
  • John_Smith
    John_Smith almost 14 years
    This was brilliant. A small question though: Could you detect if usage is set by the user or the default is used and if so add the positional args to the usage message?
  • Douglas Mayle
    Douglas Mayle almost 14 years
    I suggest you look at the argparse module... It's small enough that you can embed it in any project, and does the same as this code and much more...
  • fmark
    fmark over 13 years
    argparse is in the 2.7 standard lib