Makogan
Makogan

Reputation: 9540

Argparse not parsing boolean arguments?

I am trying to make a build script like this:

import glob
import os
import subprocess
import re
import argparse
import shutil

def create_parser():
    parser = argparse.ArgumentParser(description='Build project')

    parser.add_argument('--clean_logs', type=bool, default=True,
                        help='If true, old debug logs will be deleted.')

    parser.add_argument('--run', type=bool, default=True,
                        help="If true, executable will run after compilation.")

    parser.add_argument('--clean_build', type=bool, default=False,
                        help="If true, all generated files will be deleted and the"
                        " directory will be reset to a pristine condition.")

    return parser.parse_args()


def main():
    parser = create_parser()
    print(parser)

However no matter how I try to pass the argument I only get the default values. I always get Namespace(clean_build=False, clean_logs=True, run=True).

I have tried:

python3 build.py --run False
python3 build.py --run=FALSE
python3 build.py --run FALSE
python3 build.py --run=False
python3 build.py --run false
python3 build.py --run 'False'

It's always the same thing. What am I missing?

Upvotes: 12

Views: 15818

Answers (2)

rokpoto.com
rokpoto.com

Reputation: 10728

Argument run is initialized to True even that you pass --run False

Below code based on this great answer is workaround around this issue:

import argparse

def str2bool(v):
    if isinstance(v, bool):
        return v
    if v.lower() in ('yes', 'true', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Boolean value expected.')

def main():
    ap = argparse.ArgumentParser()
    # List of args
    ap.add_argument('--foo', type=str2bool, help='Some helpful text')
    # Importable object
    args = ap.parse_args()
    print(args.foo)


if __name__ == '__main__':
    main()

Upvotes: 6

Idea O.
Idea O.

Reputation: 480

You are misunderstanding how the argparse understands the boolean arguments.

Basically you should use action='store_true' or action='store_false' instead of the default value, with the understanding that not specifying the argument will give you the opposite of the action, e.g.

parser.add_argument('-x', type=bool, action='store_true')

will cause:

python3 command -x

to have x set to True and

python3 command

to have x set to False.

While action=store_false will do the opposite.


Setting bool as type does not behave as you expect and this is a known issue.

The reason for the current behavior is that type is expected to be a callable which is used as argument = type(argument). bool('False') evaluates to True, so you need to set a different type for the behavior you expect to happen.

Upvotes: 21

Related Questions