Argparse: Making required flags

Jacob C Boswell picture Jacob C Boswell · Oct 7, 2014 · Viewed 7.7k times · Source

I am attempting to create a required flag "-f" that accepts the input "filename.pdb" in Argparse.

This is simple enough. The standard solution is to add the option "required=True."

Unfortunately, after doing this, the "-f" flag still appears under optional arguments in the help list. Even more confusingly, the "-f" flag appears as required in the "usage" prompt in the help list.

Here is my code:

parser = argparse.ArgumentParser()

parser.add_argument("-f", "--file_name", required=True, help="enter name of .pdb file")

parser.add_argument("-bw", "--bin_width",  default=.25, help="enter desired bin width in nanometers. default = .25")

parser.add_argument("-bn","--base_name", default="IDP", help="custom prefix for output file naming. default = IDP")

args = parser.parse_args()   

And here is the help window that is returned by --help

usage: rgcalc.py [-h] -f FILE_NAME [-bw BIN_WIDTH] [-bn BASE_NAME]

optional arguments:
  -h, --help            show this help message and exit
  -f FILE_NAME, --file_name FILE_NAME
                    enter name of .pdb file
  -bw BIN_WIDTH, --bin_width BIN_WIDTH
                    enter desired bin width in nanometers. default = .25
  -bn BASE_NAME, --base_name BASE_NAME
                    custom prefix for output file naming. default = IDP

As you can see in the "usage" block, "-f" has been taken out of brackets, indicating that it is required. Despite this, "-f" still appears in the "optional arguments" section.

Is it possible to:

A) Custom format the help window to fix this

or

B) Add some code to have the flag "-f", "--file_name" appear as a positional (opposed to an optional) argument, yet still require a flag?

I read that Argparse intentionally did this to avoid positional flags, but I am supposed to do it in order to cater to traditional linux users.

Thank you kind interwebbers!

Answer

hpaulj picture hpaulj · Oct 7, 2014

This issue has been discussed in http://bugs.python.org/issue9694, 'argparse required arguments displayed under "optional arguments"'

It's a terminology issue that isn't easily resolved, due to historical practice (in UNIX as well as Python), and a lack of good alternatives.

Arguments that take a 'flag' like '-f' have historically been called options or optionals. Generally you don't use them unless you want some value that is different from the default. But 'argparse' lets you specify required=True, so now you have a 'required optional'. And with nargs='?', it is possible to have 'positionals' which are not required.

Until Python developers come up with some alternative terminology, your best choice is to use an 'ArgumentGroup', with the title and description that you like. By default the parser has 2 ArgumentGroups, 'optional arguments' and 'positional arguments'. It has to put the argument in one or the other. You can create others, and populate them as you wish.

see http://bugs.python.org/issue9694#msg132327 (post by the original argparse developer).

The 'usage' line is the one that accurately describes how arguments are used and whether they are required or not. 'ArgumentGroups' don't affect usage or parsing. They just determine how the help lines are grouped.


For your code:

parser = argparse.ArgumentParser()
req_grp = parser.add_argument_group(title='Required Optional')
req_grp.add_argument("-f", "--file_name", required=True, help="enter name of .pdb file")
parser.add_argument("-bw", "--bin_width",  default=.25, help="enter desired bin width in nanometers. default = .25")
parser.add_argument("-bn","--base_name", default="IDP", help="custom prefix for output file naming. default = IDP")
args = parser.parse_args()

"""
usage: stack26227536.py [-h] -f FILE_NAME [-bw BIN_WIDTH] [-bn BASE_NAME]

optional arguments:
  -h, --help            show this help message and exit
  -bw BIN_WIDTH, --bin_width BIN_WIDTH
                        enter desired bin width in nanometers. default = .25
  -bn BASE_NAME, --base_name BASE_NAME
                        custom prefix for output file naming. default = IDP

Required Optional:
  -f FILE_NAME, --file_name FILE_NAME
                        enter name of .pdb file
"""

Compare this with the help produced by dropping the -f flag:

usage: stack26227536.py [-h] [-bw BIN_WIDTH] [-bn BASE_NAME] file_name

positional arguments:
  file_name             enter name of .pdb file

optional arguments:
  -h, --help            show this help message and exit
  -bw BIN_WIDTH, --bin_width BIN_WIDTH
                        enter desired bin width in nanometers. default = .25
  -bn BASE_NAME, --base_name BASE_NAME
                        custom prefix for output file naming. default = IDP