Move "help" to a different Argument Group in python argparse

Question:

Currently I’m creating a directory reader program using Python.
I’m using ‘argparse’ to parse the arguments from command line. I have the following code:

parser = argparse.ArgumentParser(prog = "LS.py",
                                 usage = "%(prog)s [options] [path1 [path2 [...pathN]]]nThe paths are optional; if not given . is used.")

group = parser.add_argument_group("Options")

group.add_argument("-path", default = ".", help = argparse.SUPPRESS, metavar = "")
group.add_argument("-m", "--modified", default = False,
                    help = "show last modified date/time [default: off]",
                    metavar = "")
group.add_argument("-o ORDER", "--order=ORDER", nargs = 2, default = "name",
                    help = "order by ('name', 'n', 'modified', 'm', 'size', 's')n[default: name]",
                    metavar = "")
group.add_argument("-r", "--recursive", default = False,
                    help = "recurse into subdirectories [default: off]",
                    metavar = "")
group.add_argument("-s", "--sizes", default = False,
                   help = "show sizes [default: off]", metavar = "")

args = parser.parse_args()
return args

When called in the following manner “LS.py -h” it produces the following output:

usage: LS.py [options] [path1 [path2 [...pathN]]]
The paths are optional; if not given . is used.

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

Options:
  -m , --modified       show last modified date/time [default: off]
  -o ORDER  , --order=ORDER  
                    order by ('name', 'n', 'modified', 'm', 'size', 's')
                    [default: name]
  -r , --recursive      recurse into subdirectories [default: off]
  -s , --sizes          show sizes [default: off]

My question: Is there a way to move the default help argument into a group such as Options?
Also, I can’t seem to find a way to remove the space before the commas in the Options arguments. The ideal output is:

Usage: ls.py [options] [path1 [path2 [...pathN]]]
The paths are optional; if not given . is used.

Options:
  -h, --help            show this help message and exit
  -m, --modified        show last modified date/time [default: off]
  -o ORDER, --order=ORDER
                        order by ('name', 'n', 'modified', 'm', 'size', 's')
                        [default: name]
  -r, --recursive       recurse into subdirectories [default: off]
  -s, --sizes           show sizes [default: off]
Asked By: Night Train

||

Answers:

Sure you can do that. The trick is to just add add_help=False the the ArgumentParser constructor and then add your own help action to the group:

import argparse

parser = argparse.ArgumentParser(prog = "LS.py",
                                 usage = "%(prog)s [options] [path1 [path2 [...pathN]]]nThe paths are optional; if not given . is used.",
                                 add_help=False)

group = parser.add_argument_group("Options")

group.add_argument("-path", default = ".", help = argparse.SUPPRESS, metavar = "")
group.add_argument("-m", "--modified", default = False,
                    help = "show last modified date/time [default: off]",
                    metavar = "")
group.add_argument("-o ORDER", "--order=ORDER", nargs = 2, default = "name",
                    help = "order by ('name', 'n', 'modified', 'm', 'size', 's')n[default: name]",
                    metavar = "")
group.add_argument("-h", "--help", action='help', help='print this fabulous help message')
group.add_argument("-r", "--recursive", default = False,
                    help = "recurse into subdirectories [default: off]",
                    metavar = "")
group.add_argument("-s", "--sizes", default = False,
                   help = "show sizes [default: off]", metavar = "")

args = parser.parse_args()
Answered By: mgilson

You can use add_help=False to disable the built-in help command and add your own instead, using action="help" (thanks @mgilson!)

To get rid of the spaces, don’t set metavar to an empty string. Your options should be specified using action="store_true" to make them true (argument-less) options:

import argparse

parser = argparse.ArgumentParser(prog="LS.py",
                                 usage="%(prog)s [options] [paths...]nThe paths are optional; if not given . is used.",
                                 add_help=False)

group = parser.add_argument_group("Options")

group.add_argument("-h", "--help", action="help", help="show this help message and exit")
group.add_argument("-path", default=".", help=argparse.SUPPRESS)
group.add_argument("-m", "--modified", action="store_true",
                    help="show last modified date/time")
group.add_argument("-o", "--order", nargs=1, default="name",
                    help="sort order (n[ame], m[odified], s[ize])n[default: name]")
group.add_argument("-r", "--recursive", action="store_true",
                    help="recurse into subdirectories")
group.add_argument("-s", "--sizes", action="store_true",
                   help="show sizes")

args = parser.parse_args()

Output:

Options:
  -h, --help            show this help message and exit
  -m, --modified        show last modified date/time
  -o ORDER, --order ORDER
                        sort order (n[ame], m[odified], s[ize]) [default:
                        name]
  -r, --recursive       recurse into subdirectories
  -s, --sizes           show sizes
Answered By: nneonneo

To condense and simplify a bit upon the previous answer by nneonneo, you can have:

import argparse

parser = argparse.ArgumentParser(prog="LS.py",
                                 usage="%(prog)s [options] [paths...]nThe paths are optional; if not given . is used.",
                                 add_help=False)

add_arg = parser.add_argument_group("Options").add_argument

add_arg("-h", "--help", action="help", help="show this help message and exit")
add_arg("-path", default=".", help=argparse.SUPPRESS)
add_arg("-m", "--modified", action="store_true",
        help="show last modified date/time")
add_arg("-o", "--order", nargs=1, default="name",
        help="sort order (n[ame], m[odified], s[ize])n[default: name]")
add_arg("-r", "--recursive", action="store_true",
        help="recurse into subdirectories")
add_arg("-s", "--sizes", action="store_true",
        help="show sizes")

args = parser.parse_args()

Basically, the slight variation from the previous answer is that it is not necessary to save group and then repeatedly call the the add_argument method on it.

Answered By: Asclepius

In my case, I’m working in a module of a larger application that creates the ArgumentParser object for me so setting add_help=False isn’t an option. I can set that variable on the ArgumentParser object but that doesn’t do any good; the help argument has already been created. Instead, I did this (horrible, unsupported hack) to move it from the default "optional arguments" group into my own "Other arguments" group:

if '_action_groups' in parser.__dict__ 
   and 4 == len(parser._action_groups) 
   and 'optional arguments' == parser._action_groups[1].title 
   and 'Other arguments' == parser._action_groups[3].title 
   and '_group_actions' in parser._action_groups[1].__dict__:
    act = next((x for x in parser._action_groups[1]._group_actions if 'help' == x.dest), None)
    if None != act:
        parser._action_groups[1]._group_actions.remove(act)
        parser._action_groups[3]._group_actions.append(act)

Any and all of that may break in the next release of Python, but hopefully all of my checks will prevent any such changes from crashing the program and just make "–help" in the default "optional arguments" group.

A better version of this would search for the "optional arguments" and "Other arguments" groups rather than assuming that they’re at indices 0 and 3.

Answered By: user3553031
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.