8

I'm trying to combine configparser and argparse for a script such that the default values for the various arguments defined by argparse are stored in a config file which is manipulated via configparser. The problem I'm running into is with boolean options. argparse has the store_true and store_false actions for these options which automatically create a default and specify what to change to when the option is given. However, since the default is being read in from the config file, I don't know what it is ahead of time in order to use these actions. This would suggest something like:

import argparse,configparser

config = configparser.ConfigParser()
config['DEFAULT']['test'] = 'False'
config.read('testing.cfg')

parser = argparse.ArgumentParser()

if config.getboolean('DEFAULT','test'):
    parser.add_argument('-t',action='store_false', dest='test')
else:
    parser.add_argument('-t',action='store_true', dest='test')

args = parser.parse_args()

print(args.test)

However, I don't like the idea of having a parser.addargument statements inside a conditional (especially cumbersome the more of these options that I have). What I would prefer is a something like:

parser.add_argument('-t',action='toggle_boolean',dest='test',default=config.getboolean('DEFAULT','test'))

In this instance the toggle_boolean action would switch the state of boolean, whatever it happens to be, when the argument is given. The problem is that said action (toggle_boolean) doesn't exist. How would I go about defining such an action, or is there a better way of doing this?

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
rpspringuel
  • 251
  • 2
  • 6

1 Answers1

8

store_true and store_false are special cases of store_const:

In [213]: parser = argparse.ArgumentParser()
In [214]: foo = True
In [215]: parser.add_argument('-s', action='store_const', default=foo, const=not(foo))
In [216]: parser.add_argument('-n', action='store_const', default=not(foo), const=foo);

In [218]: parser.parse_args([])
Out[218]: Namespace(n=False, s=True)

In [219]: parser.parse_args(['-s','-n'])
Out[219]: Namespace(n=True, s=False)
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Perfect. No new lines of code needed and does exactly what I need. – rpspringuel Apr 24 '18 at 21:01
  • 3
    I would recommend writing `not foo`, instead of function-like `not(foo)`. It may not be causing problems here, but that kind of habit leads to surprises like writing `not(x) in y` and expecting it to behave like `(not x) in y` instead of `not (x in y)`. – user2357112 Apr 24 '18 at 21:13