Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Argparse custom help from text file

I want to use the argparse library because of its flexibility, but I am having trouble disabling the default help dialogue to show a custom one from a text file. All I want to do is display the text from the text file when the "-h" or "--help" option is passed. Here is an example of how I am trying this:

parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("file", type=str, nargs='+')
parser.add_argument("-xmin", type=float)
parser.add_argument("-xmax", type=float)
parser.add_argument("-ymin", type=float)
parser.add_argument("-ymax", type=float)
parser.add_argument("-h", "--help", action="store_true")

args = parser.parse_args()

if args.help is True:
    print isip_get_help()
    exit(-1)

But it still outputs:

nedc_[1]: python isip_plot_det.py -h
usage: isip_plot_det.py [-xmin XMIN] [-xmax XMAX] [-ymin YMIN] [-ymax YMAX]
                        [-h]
                        file [file ...]
isip_plot_det.py: error: too few arguments

Any ideas?

like image 424
James Mchugh Avatar asked Nov 25 '15 00:11

James Mchugh


2 Answers

What you are getting is an error message, not the help (i.e. it's not produced by your -h).

isip_plot_det.py: error: too few arguments

The error message shows the usage part of the normal help. You can change that with a usage parameter:

parser = ArgumentParser(usage = 'my custom usage line')

You can also test the usage display with

parser.print_usage()

or

astr = parser.format_usage()

to get a printable string.

The normal help argument uses a special help action class. Its call method is:

def __call__(self, parser, namespace, values, option_string=None):
    parser.print_help()
    parser.exit()

Notice that it displays the help with parser.print_help(), and then exits. That occurs as soon as it parses the -h string. That way it doesn't produce any errors like the too few arguments or unrecognized arguments (which are produced at the end of parsing).

So another way of customizing the help is to subclass ArgumentParser, and define your own print_help method. You can also customize the exit and error methods.

The default print_help is:

def print_help(self, file=None):
    if file is None:
        file = sys.stdout
    self._print_message(self.format_help(), file)

You could customize format_help instead.

 class MyParser(argparse.ArgumentParser):
     def format_help(self):
         return 'my custom help message\n   second line\n\n'

Sample usage:

In [104]: parser=MyParser(usage='custom usage')
In [105]: parser.parse_args(['-h'])
my custom help message
   second line
   ...

In [106]: parser.parse_args(['unknown'])
usage: custom usage
ipython3: error: unrecognized arguments: unknown
...
like image 120
hpaulj Avatar answered Sep 21 '22 10:09

hpaulj


The failure is caused by the missing required argument file. The reason why action would not be subjected to this validation requirement is simply because they are executed first, i,e, args.help will be set to True. However, once the parser completes parsing the arguments it would have triggered a sys.exit due to validation failure, and this ends with printing out the default usage and your code (that prints your desired help message) will simply never be executed (you can try calling your program as is with a -h file arguments and your help message should print).

You can either add your custom action using parser.register (not officially supported as it's considered private API, but it works - read argparse.py to see how it all works), or alternatively subclass ArgumentParser and override the print_help method to call isip_get_help().

You could try something like this:

class MyArgumentParser(argparse.ArgumentParser):

    def print_help(self, file=None):
        print(isip_get_help())
        exit(-1)

parser = MyArgumentParser()
...

Leave the default add_help in, but with print_help overridden to call your custom help it should work.

like image 26
metatoaster Avatar answered Sep 19 '22 10:09

metatoaster