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