I am trying to get the following behaviour:
python test.py
⟹ store foo=False
python test.py --foo
⟹ store foo=True
python test.py --foo bool
⟹ store foo=bool
It works when I use
parser.add_argument('--foo', nargs='?', default=False, const=True)
However, it breaks if I add type=bool
, trying to enforce casting to boolean. In this case
python test.py --foo False
Actually ends up storing foo=True
. What's going on??
Optional Arguments To add an optional argument, simply omit the required parameter in add_argument() . args = parser. parse_args()if args.
The boolean value is always assigned, so that it can be used in logical statements without checking beforehand: import argparse parser = argparse. ArgumentParser(description="Parse bool") parser. add_argument("--do-something", default=False, action="store_true", help="Flag to do something") args = parser.
Python argparse optional argument The example adds one argument having two options: a short -o and a long --ouput . These are optional arguments. The module is imported. An argument is added with add_argument .
You can either use the action with store_true | store_false , or you can use an int and let implicit casting check a boolean value. Using the action , you wouldn't pass a --foo=true and --foo=false argument, you would simply include it if it was to be set to true.
Are you sure you need that pattern? --foo
and --foo <value>
, together, for a boolean switch, is not a common pattern to use.
As for your issue, remember that the command line value is a string and, type=bool
means that you want bool(entered-string-value)
to be applied. For --foo False
that means bool("False")
, producing True
; all non-empty strings are true! See Why is argparse not parsing my boolean flag correctly? as well.
Instead of supporting --foo
/ --foo <string value>
, I would strongly recommend you use --foo
to mean True
, drop the argument value, and instead add a --no-foo
option to explicitly set False
:
parser.add_argument('--foo', default=False, action='store_true') parser.add_argument('--no-foo', dest='foo', action='store_false')
The dest='foo'
addition on the --no-foo
switch ensures that the False
value it stores (via store_false
) ends up on the same args.foo
attribute.
As of Python 3.9, you can also use the argparse.BooleanOptionalAction
action class:
parser.add_argument("--foo", action=argparse.BooleanOptionalAction)
and it'll have the same effect, handling --foo
and --no-foo
to set and clear the flag.
You'd only need a --foo / --no-foo
combination if you have some other configuration mechanism that would set foo
to True
and you needed to override this again with a command-line switch. --no-<option>
is a widely adopted standard to invert a boolean command-line switch.
If you don't have a specific need for a --no-foo
inverted switch (since just omitting --foo
would already mean 'false'), then just stick with the action='store_true'
option. This keeps your command line simple and clear!
However, if your use case or other constraints specifically require that your command line must have some king of --foo (true|false|0|1)
support, then add your own converter:
def str_to_bool(value): if isinstance(value, bool): return value if value.lower() in {'false', 'f', '0', 'no', 'n'}: return False elif value.lower() in {'true', 't', '1', 'yes', 'y'}: return True raise ValueError(f'{value} is not a valid boolean value') parser.add_argument('--foo', type=str_to_bool, nargs='?', const=True, default=False)
const
value is used for nargs='?'
arguments where the argument value is omitted. Here that sets foo=True
when --foo
is used.default=False
is used when the switch is not used at all.type=str_to_bool
is used to handle the --foo <value>
case.Demo:
$ cat so52403065.py from argparse import ArgumentParser parser = ArgumentParser() def str_to_bool(value): if value.lower() in {'false', 'f', '0', 'no', 'n'}: return False elif value.lower() in {'true', 't', '1', 'yes', 'y'}: return True raise ValueError(f'{value} is not a valid boolean value') parser.add_argument('--foo', type=str_to_bool, nargs='?', const=True, default=False) print(parser.parse_args()) $ python so52403065.py Namespace(foo=False) $ python so52403065.py --foo Namespace(foo=True) $ python so52403065.py --foo True Namespace(foo=True) $ python so52403065.py --foo no Namespace(foo=False) $ python so52403065.py --foo arrbuggrhellno usage: so52403065.py [-h] [--foo [FOO]] so52403065.py: error: argument --foo: invalid str_to_bool value: 'arrbuggrhellno'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With