45

Here is the simplest Python script, named test.py:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--bool', default=True, type=bool, help='Bool type')
args = parser.parse_args()
print(args.bool)

But when I run this code on the command line:

python test.py --bool False
True

Whereas when my code reads '--bool', default=False, the argparse runs correctly.

Why?

Seanny123
  • 8,776
  • 13
  • 68
  • 124
Lu Zhang
  • 471
  • 1
  • 4
  • 5

1 Answers1

70

You are not passing in the False object. You are passing in the 'False' string, and that's a string of non-zero length.

Only a string of length 0 tests as false:

>>> bool('')
False
>>> bool('Any other string is True')
True
>>> bool('False')  # this includes the string 'False'
True

Use a store_true or store_false action instead. For default=True, use store_false:

parser.add_argument('--bool', default=True, action='store_false', help='Bool type')

Now omitting the switch sets args.bool to True, using --bool (with no further argument) sets args.bool to False:

python test.py
True

python test.py --bool
False

If you must parse a string with True or False in it, you'll have to do so explicitly:

def boolean_string(s):
    if s not in {'False', 'True'}:
        raise ValueError('Not a valid boolean string')
    return s == 'True'

and use that as the conversion argument:

parser.add_argument('--bool', default=True, type=boolean_string, help='Bool type')

at which point --bool False will work as you expect it to.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 5
    The standard library function `distutils.util.strtobool()` function can be used instead of `boolean_string()` and also supports strings like "yes" and "no" (although it returns an int of 0 or 1 so you might still want to wrap it if you really need a proper bool) – Levi May 24 '20 at 18:57