bw2 / ConfigArgParse

A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables.
MIT License
719 stars 121 forks source link

[bug]Cannot override yaml settings on the command line when using the bool option with strtobool. #259

Open MasanoriYamada opened 2 years ago

MasanoriYamada commented 2 years ago

Since bool is difficult to handle on argparse, there is a way to use the strtobool function.

check.py

import configargparse
from distutils.util import strtobool

def strtointtobool(x):
    return bool(strtobool(x))

def parse_args():
    cp = configargparse.ArgumentParser(default_config_files=[])
    cp.add_argument('-c', '--conf', dest='config', is_config_file=True, help='config file path')
    cp.add_argument('-f', '--flag', dest='flag', type=strtointtobool)
    cp.add_argument('-a', '--array', dest='array', type=int, nargs='+', default=[], help='array parama')
    return cp.parse_args()

args = parse_args()
print(args)
print(type(args.flag))

It works intuitively.

➜ python check.py -f True
Namespace(config=None, flag=True, array=[])
<class 'bool'>
➜ python check.py -f False
Namespace(config=None, flag=False, array=[])
<class 'bool'>

Issue

If you set a value in setting.yaml, it cannot be overridden by command line options. This is different from the normal behavior of configargparse. This happens when used with array type

setting.yaml

array: [1, 12, 35, 40]
f: True
➜  python check.py -c setting.yaml
Namespace(config='setting.yaml', flag=True, array=[1, 12, 35, 40])
<class 'bool'>
➜ python check.py -c setting.yaml -f True
Namespace(config='setting.yaml', flag=True, array=[1, 12, 35, 40])
<class 'bool'>
➜ python check.py -c setting.yaml -f False  # problem
Namespace(config='setting.yaml', flag=True, array=[1, 12, 35, 40])
<class 'bool'>

The -f False option on the command line has been overwritten by setting.yaml

If you don't use the array option, it will work as expected.

setting.yaml

f: True
➜ python check.py -c setting.yaml -f False
Namespace(config='setting.yaml', flag=False, array=[])
<class 'bool'>

gist: https://gist.github.com/MasanoriYamada/a50dd8276b0f5cf56e32aa5932b93ae5

MasanoriYamada commented 2 years ago

If you use only the --f option as in cp.add_argument('--f', dest='flag', type=strtointtobool) , it works as expected