Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend argparse to write set names in the help text for optional argument choices and define those sets once at the end

Example of the problem

If I have a list of valid option strings which is shared between several arguments, the list is written in multiple places in the help string. Making it harder to read:

def main():
    elements = ['a', 'b', 'c', 'd', 'e', 'f']

    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-i',
        nargs='*',
        choices=elements,
        default=elements,
        help='Space separated list of case sensitive element names.')
    parser.add_argument(
        '-e',
        nargs='*',
        choices=elements,
        default=[],
        help='Space separated list of case sensitive element names to '
        'exclude from processing')

    parser.parse_args()

When running the above function with the command line argument --help it shows:

usage: arguments.py [-h] [-i [{a,b,c,d,e,f} [{a,b,c,d,e,f} ...]]]
                    [-e [{a,b,c,d,e,f} [{a,b,c,d,e,f} ...]]]

optional arguments:
  -h, --help            show this help message and exit
  -i [{a,b,c,d,e,f} [{a,b,c,d,e,f} ...]]
                        Space separated list of case sensitive element names.
  -e [{a,b,c,d,e,f} [{a,b,c,d,e,f} ...]]
                        Space separated list of case sensitive element names
                        to exclude from processing

What would be nice

It would be nice if one could define an option list name, and in the help output write the option list name in multiple places and define it last of all. In theory it would work like this:

def main_optionlist():
    elements = ['a', 'b', 'c', 'd', 'e', 'f']

    # Two instances of OptionList are equal if and only if they
    # have the same name (ALFA in this case)

    ol = OptionList('ALFA', elements)

    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-i',
        nargs='*',
        choices=ol,
        default=ol,
        help='Space separated list of case sensitive element names.')
    parser.add_argument(
        '-e',
        nargs='*',
        choices=ol,
        default=[],
        help='Space separated list of case sensitive element names to '
        'exclude from processing')

    parser.parse_args()

And when running the above function with the command line argument --help it would show something similar to:

usage: arguments.py [-h] [-i [ALFA [ALFA ...]]]
                    [-e [ALFA [ALFA ...]]]

optional arguments:
  -h, --help            show this help message and exit
  -i [ALFA [ALFA ...]]
                        Space separated list of case sensitive element names.
  -e [ALFA [ALFA ...]]
                        Space separated list of case sensitive element names
                        to exclude from processing
sets in optional arguments:
  ALFA                  {a,b,c,d,e,f}

Question

I need to:

  • Replace the {'l', 'i', 's', 't', 's'} shown with the option name, in the optional arguments.
  • At the end of the help text show a section explaining which elements each option name consists of.

So I ask:

  1. Is this possible using argparse?
  2. Which classes would I have to inherit from and which methods would I need to override?

I have tried looking at the source for argparse, but as this modification feels pretty advanced I don´t know how to get going.

like image 424
Deleted Avatar asked Mar 14 '12 12:03

Deleted


1 Answers

My answer doesn't attempt to extend argparse at all, but rather uses the available options of argparse as it is... Does this solve your situation?

import argparse
import textwrap

def main():
    elements = ['a', 'b', 'c', 'd', 'e', 'f']

    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog = textwrap.dedent('''\
            sets in optional arguments: 
                ALFA\t\t{a,b,c,d,e,f}"
            '''))

    parser.add_argument(
        '-i',
        nargs='*',
        choices=elements,
        default=elements,
        metavar="ALFA",
        help='Space separated list of case sensitive element names.')
    parser.add_argument(
        '-e',
        nargs='*',
        choices=elements,
        default=[],
        metavar="ALFA",
        help='Space separated list of case sensitive element names to '
        'exclude from processing')

    parser.parse_args()

Output

usage: test.py [-h] [-i [ALFA [ALFA ...]]] [-e [ALFA [ALFA ...]]]

optional arguments:
  -h, --help            show this help message and exit
  -i [ALFA [ALFA ...]]  Space separated list of case sensitive element names.
  -e [ALFA [ALFA ...]]  Space separated list of case sensitive element names
                        to exclude from processing

sets in optional arguments: 
    ALFA                {a,b,c,d,e,f}"

The nice thing about this approach is that you can freely name the metavar whatever you want for each flag, and you can manually format the epilog to reflect any format description as well. No subclassing needed.

like image 153
jdi Avatar answered Oct 21 '22 03:10

jdi