Search code examples
python-3.xbooleanargparse

parser.parse_args boolean parse "False" as True


When I run my python code with -rm False I still see _REMOVE_ADS = True.

How can I fix this?

parser.add_argument(
    "-rm",
    "--remove_ads",
    type=bool,
    required=False,
    default=False,
    help="Should remove disapproved ads. Default: false",
)
# TODO: Fix booleans
args = parser.parse_args()
_REMOVE_ADS = args.remove_ads
print(_REMOVE_ADS)

Solution

  • This is because they are parsed as strings and any non-empty string is considered True by bool:

    >>> bool("False")
    True
    

    To fix it, use a different type instead of type=bool, for Python < 3.10 there is a standard lib option which can be used:

    from distutils.util import strtobool
    

    You can register this type with a name on a parser instance:

    from distutils.util import strtobool
    
    parser = ArgumentParser(...)
    parser.register('type', 'boolean', strtobool)
    parser.add_argument('-rm', type='boolean')
    

    Alternatively, just make this option into a flag so it doesn't need to accept an argument at all, although note that this does change your CLI usage syntax:

    parser.add_argument(
        "-rm", "--remove-ads",
        action="store_true",
        help="Should remove disapproved ads",
    )
    

    In Python 3.10 the distutils module has been deprecated. The Migration Advice section of PEP-632 says there is no replacement for the strtobool function and you will need to re-implement the functionality yourself, but that should be easy enough (tweak as necessary):

    def strtobool(val): 
        if val.lower().startswith("t"): 
            return True 
        elif val.lower().startswith("f"): 
            return False 
        raise argparse.ArgumentTypeError("invalid boolean value: {!r}".format(val))