'Adding extra description between argparse optional arguments

I'd like to add an extra description between optional argument groups in argaparse in a following style:

script --help
usage: script [options] <COMMAND>

A script

optional arguments:
  -h, --help            show this help message and exit
  -f FOO, --foo FOO     show FOO
following commands modify FOO output:
  -lower                show FOO in lowercase
  -upper                show FOO in CAPS
following commands redirect FOO:
  -to-file              write FOO to file
                   


Solution 1:[1]

Well, I guess you've already made something as you mentioned argparse in your question title and your output sample looks quite similar to something which have been generated using ArgumentParser. If you want just a code sample, you could take it from comment I've left, but I've decided to add some explanation.

Basically the solution of your problem is creating separate groups using ArgumentParser.add_argument_group(). Text you pass to description argument will be printed before help for arguments added to this group (exactly how you wanted besides some extra newlines).

Now some tips regarding implementation for this particular case.

Since --lower and --upper arguments should just store a boolean value, I'd recommend to set same destination for both arguments (e.g. is_lower) and use store_true/store_false action. Also as logically only one of these arguments could be used at the same time it'd be a good idea to add both into a mutually exclusive group using ArgumentParser.add_mutually_exclusive_group(). Code:

from argparse import ArgumentParser

...

parser = ArgumentParser(description="A script")

...

modify_group = parser.add_argument_group(
    description="following commands modify FOO output:"
)
modify_exclusive_group = modify_group.add_mutually_exclusive_group()
modify_exclusive_group.add_argument(
    "--lower",
    action="store_true",
    dest="is_lower",
    default=True,
    help="show FOO in lowercase"
)
modify_exclusive_group.add_argument(
    "--upper",
    action="store_false",
    dest="is_lower",
    help="show FOO in CAPS"
)

With --to-file argument situation is quite different. First of all, I'd not add it at all, as output redirection could be done in console (python script.py > out.txt). But if you still want to implement it, you might use special file type argparse.FileType which let parser to open file handle in certain mode. Depending on your code you might use opened file in any of possible way, I'd show common way to redirect all output into a file by replacing sys.stdout with opened file object. Code:

import sys
from argparse import FileType

...

redirect_group = parser.add_argument_group(
    description="following commands redirect FOO:"
)
redirect_group.add_argument(
    "--to-file",
    type=FileType("w"),
    dest="stdout",
    default=sys.stdout,
    help="write FOO to file",
    metavar=""  # set name here to add variable in help message
)

...

args = parser.parse_args()
sys.stdout = args.stdout

Combining all together and adding some simple task to print random strings you will get next code:

import sys
from argparse import ArgumentParser, FileType
from random import randrange, choices
from string import ascii_letters

parser = ArgumentParser(description="A script")
parser.add_argument("-f", "--foo", help="show FOO")
modify_group = parser.add_argument_group(
    description="following commands modify FOO output:"
)
modify_exclusive_group = modify_group.add_mutually_exclusive_group()
modify_exclusive_group.add_argument(
    "--lower", 
    action="store_true", 
    dest="is_lower", 
    default=True,
    help="show FOO in lowercase"
)
modify_exclusive_group.add_argument(
    "--upper",
    action="store_false",
    dest="is_lower",
    help="show FOO in CAPS"
)
redirect_group = parser.add_argument_group(
    description="following commands redirect FOO:"
)
redirect_group.add_argument(
    "--to-file",
    type=FileType("w"),
    dest="stdout",
    default=sys.stdout,
    help="write FOO to file",
    metavar=""
)

args = parser.parse_args()
sys.stdout = args.stdout
modify_method = str.lower if args.is_lower else str.upper

for _ in range(randrange(5, 10)):
    random_string = "".join(choices(ascii_letters, k=randrange(10, 20)))
    print(modify_method(random_string))

Help message:

usage: script.py [-h] [-f FOO] [--lower | --upper] [--to-file]

A script

optional arguments:
  -h, --help         show this help message and exit
  -f FOO, --foo FOO  show FOO

  following commands modify FOO output:

  --lower            show FOO in lowercase
  --upper            show FOO in CAPS

  following commands redirect FOO:

  --to-file          write FOO to file

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Olvin Roght