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

cdleary picture cdleary · Mar 13, 2009 · Viewed 10k times · Source

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. :-)

Answer

Douglas Mayle picture Douglas Mayle · Mar 20, 2009

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