argparse positional argument with nargs set to '?'
Question:
I want to make a list command that lists all items with:
python file.py list
I also want it to accept a filter query e.g. to list all items with the string "cat" in it would be:
python file.py list cat
I have done the following to achieve this, which seems to work:
parser = argparse.ArgumentParser()
parser.add_argument("action", choices=["list"])
parser.add_argument("query",type=str,nargs='?')
I am curious to know why it is allowed to create a positional argument query, with the possibility of not suppling anything for it by using nargs=’?’? I mean, positional arguments have required=True by default and setting required=False is not allowed.
Answers:
Don’t get too focused on the "required". The fundamental distinction in argparse
(other POSIX style parsers) is between "flagged" arguments, and "positionals". "flagged", also commonly called "optionals", take some sort of flag string, commonly prefixed with a dash or two (though this can be changed). A "positional" is "identified" by position, that is word order. Some parsers require a specific order, either all options first, or all after, the positionals. argparse
shows positionals after optionals in the usage, but tries, where possible, to handle any order.
argparse
also provides a required
parameter for flagged arguments, and allows nargs
like ‘?’, ‘+’, ‘*’, ‘…’, that handle a variable number of arguments. And some flagged ones don’t take any argument (True/False).
Help group names like "required", "optional", "positional" don’t reflect all possibilites, so don’t take them too literally.
A simple script that takes two file names, and one or more control values might look something like this:
In [1]: import argparse
In [2]: parser = argparse.ArgumentParser()
...: parser.add_argument('-f','--foo')
...: parser.add_argument('input')
...: parser.add_argument('output', nargs='?', default='outfile')
‘[]’ are used in usage to give a hit as to which strings are required, and which may be omitted. If I defined a ‘-g’ with required=True
, it would still be grouped with optional
, since it is not a positional
.
In [3]: parser.print_help()
usage: ipykernel_launcher.py [-h] [-f FOO] input [output]
positional arguments:
input
output
optional arguments:
-h, --help show this help message and exit
-f FOO, --foo FOO
Sample runs:
In [4]: parser.parse_args([])
usage: ipykernel_launcher.py [-h] [-f FOO] input [output]
ipykernel_launcher.py: error: the following arguments are required: input
...
In [5]: parser.parse_args('in'.split())
Out[5]: Namespace(foo=None, input='in', output='outfile')
In [6]: parser.parse_args('in out -f foobar'.split())
Out[6]: Namespace(foo='foobar', input='in', output='out')
All defined arguments can be seen in the _actions
list, and each has a ‘required’ attribute:
In [8]: parser._actions
Out[8]:
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
_StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None),
_StoreAction(option_strings=[], dest='input', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None),
_StoreAction(option_strings=[], dest='output', nargs='?', const=None, default='outfile', type=None, choices=None, help=None, metavar=None)]
In [9]: [a.required for a in parser._actions]
Out[9]: [False, False, True, False]
The output
positional is not required
, because of its nargs
value.
I want to make a list command that lists all items with:
python file.py list
I also want it to accept a filter query e.g. to list all items with the string "cat" in it would be:
python file.py list cat
I have done the following to achieve this, which seems to work:
parser = argparse.ArgumentParser()
parser.add_argument("action", choices=["list"])
parser.add_argument("query",type=str,nargs='?')
I am curious to know why it is allowed to create a positional argument query, with the possibility of not suppling anything for it by using nargs=’?’? I mean, positional arguments have required=True by default and setting required=False is not allowed.
Don’t get too focused on the "required". The fundamental distinction in argparse
(other POSIX style parsers) is between "flagged" arguments, and "positionals". "flagged", also commonly called "optionals", take some sort of flag string, commonly prefixed with a dash or two (though this can be changed). A "positional" is "identified" by position, that is word order. Some parsers require a specific order, either all options first, or all after, the positionals. argparse
shows positionals after optionals in the usage, but tries, where possible, to handle any order.
argparse
also provides a required
parameter for flagged arguments, and allows nargs
like ‘?’, ‘+’, ‘*’, ‘…’, that handle a variable number of arguments. And some flagged ones don’t take any argument (True/False).
Help group names like "required", "optional", "positional" don’t reflect all possibilites, so don’t take them too literally.
A simple script that takes two file names, and one or more control values might look something like this:
In [1]: import argparse
In [2]: parser = argparse.ArgumentParser()
...: parser.add_argument('-f','--foo')
...: parser.add_argument('input')
...: parser.add_argument('output', nargs='?', default='outfile')
‘[]’ are used in usage to give a hit as to which strings are required, and which may be omitted. If I defined a ‘-g’ with required=True
, it would still be grouped with optional
, since it is not a positional
.
In [3]: parser.print_help()
usage: ipykernel_launcher.py [-h] [-f FOO] input [output]
positional arguments:
input
output
optional arguments:
-h, --help show this help message and exit
-f FOO, --foo FOO
Sample runs:
In [4]: parser.parse_args([])
usage: ipykernel_launcher.py [-h] [-f FOO] input [output]
ipykernel_launcher.py: error: the following arguments are required: input
...
In [5]: parser.parse_args('in'.split())
Out[5]: Namespace(foo=None, input='in', output='outfile')
In [6]: parser.parse_args('in out -f foobar'.split())
Out[6]: Namespace(foo='foobar', input='in', output='out')
All defined arguments can be seen in the _actions
list, and each has a ‘required’ attribute:
In [8]: parser._actions
Out[8]:
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
_StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None),
_StoreAction(option_strings=[], dest='input', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None),
_StoreAction(option_strings=[], dest='output', nargs='?', const=None, default='outfile', type=None, choices=None, help=None, metavar=None)]
In [9]: [a.required for a in parser._actions]
Out[9]: [False, False, True, False]
The output
positional is not required
, because of its nargs
value.