python - Argparse: Required arguments listed under "optional arguments"?

ID : 10177

viewed : 48

Tags : pythonargparsepython

Top 5 Answer for python - Argparse: Required arguments listed under "optional arguments"?

vote vote

98

Parameters starting with - or -- are usually considered optional. All other parameters are positional parameters and as such required by design (like positional function arguments). It is possible to require optional arguments, but this is a bit against their design. Since they are still part of the non-positional arguments, they will still be listed under the confusing header “optional arguments” even if they are required. The missing square brackets in the usage part however show that they are indeed required.

See also the documentation:

In general, the argparse module assumes that flags like -f and --bar indicate optional arguments, which can always be omitted at the command line.

Note: Required options are generally considered bad form because users expect options to be optional, and thus they should be avoided when possible.

That being said, the headers “positional arguments” and “optional arguments” in the help are generated by two argument groups in which the arguments are automatically separated into. Now, you could “hack into it” and change the name of the optional ones, but a far more elegant solution would be to create another group for “required named arguments” (or whatever you want to call them):

parser = argparse.ArgumentParser(description='Foo') parser.add_argument('-o', '--output', help='Output file name', default='stdout') requiredNamed = parser.add_argument_group('required named arguments') requiredNamed.add_argument('-i', '--input', help='Input file name', required=True) parser.parse_args(['-h']) 
usage: [-h] [-o OUTPUT] -i INPUT  Foo  optional arguments:   -h, --help            show this help message and exit   -o OUTPUT, --output OUTPUT                         Output file name  required named arguments:   -i INPUT, --input INPUT                         Input file name 
vote vote

90

Since I prefer to list required arguments before optional, I hack around it via:

parser = argparse.ArgumentParser() parser._action_groups.pop() required = parser.add_argument_group('required arguments') optional = parser.add_argument_group('optional arguments') required.add_argument('--required_arg', required=True) optional.add_argument('--optional_arg') return parser.parse_args() 

and this outputs:

usage: main.py [-h] --required_arg REQUIRED_ARG [--optional_arg OPTIONAL_ARG]  required arguments:   --required_arg REQUIRED_ARG  optional arguments:   --optional_arg OPTIONAL_ARG 

I can live without -h, --help showing up in the optional arguments group.

vote vote

79

Building off of @Karl Rosaen

parser = argparse.ArgumentParser() optional = parser._action_groups.pop() # Edited this line required = parser.add_argument_group('required arguments') # remove this line: optional = parser... required.add_argument('--required_arg', required=True) optional.add_argument('--optional_arg') parser._action_groups.append(optional) # added this line return parser.parse_args() 

and this outputs:

usage: main.py [-h] [--required_arg REQUIRED_ARG]            [--optional_arg OPTIONAL_ARG]  required arguments:   --required_arg REQUIRED_ARG  optional arguments:   -h, --help                    show this help message and exit   --optional_arg OPTIONAL_ARG 
vote vote

65

One more time, building off of @RalphyZ

This one doesn't break the exposed API.

from argparse import ArgumentParser, SUPPRESS # Disable default help parser = ArgumentParser(add_help=False) required = parser.add_argument_group('required arguments') optional = parser.add_argument_group('optional arguments')  # Add back help  optional.add_argument(     '-h',     '--help',     action='help',     default=SUPPRESS,     help='show this help message and exit' ) required.add_argument('--required_arg', required=True) optional.add_argument('--optional_arg') 

Which will show the same as above and should survive future versions:

usage: main.py [-h] [--required_arg REQUIRED_ARG]            [--optional_arg OPTIONAL_ARG]  required arguments:   --required_arg REQUIRED_ARG  optional arguments:   -h, --help                    show this help message and exit   --optional_arg OPTIONAL_ARG 
vote vote

52

by default there're 2 argument groups in parser._action_groups: positional arguments and named arguments (titled 'optional arguments'). you can add your named optional arguments to the existing 'optional arguments' group, and required named arguments to a new 'required arguments' group. After that you can re-order groups:

import argparse  parser = argparse.ArgumentParser(description='Foo')  required = parser.add_argument_group('required arguments')  required.add_argument('-i','--input', help='Input file name', required=True) parser.add_argument('-o','--output', help='Output file name', default="stdout")  groups_order = {     'positional arguments': 0,     'required arguments': 1,     'optional arguments': 2 } parser._action_groups.sort(key=lambda g: groups_order[g.title])  parser.parse_args(['-h']) 

output:

usage: argparse_argument_groups.py [-h] -i INPUT [-o OUTPUT]  Foo  required arguments:   -i INPUT, --input INPUT                         Input file name  optional arguments:   -h, --help            show this help message and exit   -o OUTPUT, --output OUTPUT                         Output file name 

Top 3 video Explaining python - Argparse: Required arguments listed under "optional arguments"?

Related QUESTION?