python – Parsing boolean values with argparse

python – Parsing boolean values with argparse

I think a more canonical way to do this is via:

command --feature

and

command --no-feature

argparse supports this version nicely:

Python 3.9+:

parser.add_argument(--feature, action=argparse.BooleanOptionalAction)

Python < 3.9:

parser.add_argument(--feature, action=store_true)
parser.add_argument(--no-feature, action=store_false)
parser.set_defaults(feature=True)

Of course, if you really want the --arg <True|False> version, you could pass ast.literal_eval as the type, or a user defined function …

def t_or_f(arg):
    ua = str(arg).upper()
    if TRUE.startswith(ua):
       return True
    elif FALSE.startswith(ua):
       return False
    else:
       pass  #error condition maybe?

Yet another solution using the previous suggestions, but with the correct parse error from 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.)

This is very useful to make switches with default values; for instance

parser.add_argument(--nice, type=str2bool, nargs=?,
                        const=True, default=False,
                        help=Activate nice mode.)

allows me to use:

script --nice
script --nice <bool>

and still use a default value (specific to the user settings). One (indirectly related) downside with that approach is that the nargs might catch a positional argument — see this related question and this argparse bug report.

python – Parsing boolean values with argparse

If you want to allow --feature and --no-feature at the same time (last one wins)

This allows users to make a shell alias with --feature, and overriding it with --no-feature.

Python 3.9 and above

parser.add_argument(--feature, default=True, action=argparse.BooleanOptionalAction)

Python 3.8 and below

I recommend mgilsons answer:

parser.add_argument(--feature, dest=feature, action=store_true)
parser.add_argument(--no-feature, dest=feature, action=store_false)
parser.set_defaults(feature=True)

If you DONT want to allow --feature and --no-feature at the same time

You can use a mutually exclusive group:

feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument(--feature, dest=feature, action=store_true)
feature_parser.add_argument(--no-feature, dest=feature, action=store_false)
parser.set_defaults(feature=True)

You can use this helper if you are going to set many of them:

def add_bool_arg(parser, name, default=False):
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument(-- + name, dest=name, action=store_true)
    group.add_argument(--no- + name, dest=name, action=store_false)
    parser.set_defaults(**{name:default})

add_bool_arg(parser, useful-feature)
add_bool_arg(parser, even-more-useful-feature)

Leave a Reply

Your email address will not be published. Required fields are marked *