I was adding some notes to description and epilogue to OptionParser for a script of mine, but I realized that the default formatter IndentedHelpFormatter doesn’t allow you to have line feeds because it simply uses textwrap.fill().

Here is a list of drawbacks of IndentedHelpFormatter:

  • No wrapping for usage. (Though, this isn’t necessary, it’s easy to have wrapping. For explanation of usage, it should goes into description.)
  • No %prog expansion for description, epilogue, and option help.
  • Line feeds are ripped from all except in usage and description.

Considering the follow example,

#!/usr/bin/env python
import optparse

usage = '''%prog [options]
second line of usage
third line of usage:  Lorem ipsum dolor sit amet, consectetur adipiscing \
elit. Curabitur euismod, mi quis varius suscipit, ante mauris sollicitudin \
elit, ut tempus mauris purus eu libero.

fifth line of usage'''

description = '''Description of %prog: Line1
Line2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur \
euismod, mi quis varius suscipit, ante mauris sollicitudin elit, ut tempus \
mauris purus eu libero.
Line3'''

epilog = '''Epilog of %prog: Lorem ipsum dolor sit amet, consectetur \
adipiscing elit. Curabitur euismod, mi quis varius suscipit, ante mauris \
sollicitudin elit, ut tempus mauris purus eu libero.

Last line of epilog.'''

parser = optparse.OptionParser(usage=usage, description=description,
    epilog=epilog)
parser.add_option('--simple', type='str', dest='foo',
    help='Simple option of %prog')
parser.add_option('--complex', type='str', dest='bar',
    help='''Complex option of %prog, multi-line.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur \
euismod, mi quis varius suscipit, ante mauris sollicitudin elit, ut \
tempus mauris purus eu libero.''')

options, args = parser.parse_args()

The help message is:

Usage: test.py [options]
second line of usage
third line of usage:  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur euismod, mi quis varius suscipit, ante mauris sollicitudin elit, ut tempus mauris purus eu libero.

fifth line of usage

Description of test.py: Line1 Line2 Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Curabitur euismod, mi quis varius suscipit, ante mauris
sollicitudin elit, ut tempus mauris purus eu libero. Line3

Options:
  -h, --help     show this help message and exit
  --simple=FOO   Simple option of %prog
  --complex=BAR  Complex option of %prog, multi-line.  Lorem ipsum dolor sit
                 amet, consectetur adipiscing elit. Curabitur euismod, mi quis
                 varius suscipit, ante mauris sollicitudin elit, ut tempus
                 mauris purus eu libero.

Epilog of %prog: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Curabitur euismod, mi quis varius suscipit, ante mauris sollicitudin elit, ut
tempus mauris purus eu libero.  Last line of epilog.

As you can see the usage isn’t wrapped but line feeds still in place. Description and epilogue are both wrapped but line feeds are gone. %prog isn’t expanded to program name in help option and epilogue.

I created a new class for improvements, BetterFormatter(). We uses this new formatter,

parser = optparse.OptionParser(formatter=BetterFormatter(), usage=usage,
    description=description, epilog=epilog)

Everything is wrapped and indented correctly, line feeds still in place. %prog is expanded:

Usage: test.py [options]
second line of usage
third line of usage:  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Curabitur euismod, mi quis varius suscipit, ante mauris sollicitudin elit, ut
tempus mauris purus eu libero.

fifth line of usage

Description of test.py: Line1
Line2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur
euismod, mi quis varius suscipit, ante mauris sollicitudin elit, ut tempus
mauris purus eu libero.
Line3

Options:
  -h, --help     show this help message and exit
  --simple=FOO   Simple option of test.py
  --complex=BAR  Complex option of test.py, multi-line.

                 Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                 Curabitur euismod, mi quis varius suscipit, ante mauris
                 sollicitudin elit, ut tempus mauris purus eu libero.

Epilog of test.py: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Curabitur euismod, mi quis varius suscipit, ante mauris sollicitudin elit, ut
tempus mauris purus eu libero.

Last line of epilog.

I wanted to write this code because I wasn’t satisfied by this answer and this compact version. That resolution gives you the epilogue exactly you give to your parser. The problem is wrapping is gone. You don’t really want to manually wrap your text, do you?

In the beginning, I overrode those formatting function, but I decided to also make option help to have multi-line, therefore it’s better to inherit class. That’s how I have this code.

I am not sure about argparse. I haven’t used it even optparse is deprecated, Python 2.5/2.6 doesn’t have argparse and optparse is still shipped with Python 3. I don’t know if I can simply replace the module names. But for better compatibility, I will stick with optparse. (Actual meaning is I am too lazy to code for more.)