I need to be able to accept some options from either the command-line or a config-file.
This code is a snippet of the class that I am working on, I cannot post the entire class here. This code works, but I am wondering if it can be made better. I will need to have a class here, there is a lot more work that goes on in the real code, I have pulled out just the parsing stuff. Please note, there are also several more sub-parsers that I will need, but the sub-parser shown is the only one that will possibly use a config file.
There is an issue with argparse with nesting argument_groups and mutually_exclusive_groups. So, I am not trying to use mutually-exclusive, but I am checking that with my own code in the functions.
import argparse
import yaml
from pprint import pprint
_possible_config_file_keys = ('names', 'ids')
class Parser(object):
def __init__(self):
self.build_parser()
self.options = self.parse_args()
#do other stuff here using self.options
def build_parser(self):
self.root_parser = argparse.ArgumentParser(description="Tool for ...")
self.root_sub_parsers = self.root_parser.add_subparsers(dest='action')
self.add_person_parser()
self.add_other_parser()
def add_person_parser(self):
parser = self.root_sub_parsers.add_parser('People')
g = parser.add_argument_group('People Targets')
g.add_argument(
"--config-file",
help='Supply a config file',
type=argparse.FileType(mode='r'))
g.add_argument('--name', dest='names', default=[], action='append')
g.add_argument('--id', dest='ids', default=[], action='append')
def add_other_parser(self):
pass #would do actual work here and add more subparsers
def parse_args(self):
args = self.parse_command_line_args()
if args.config_file:
self.parse_config_file(args)
delattr(args, 'config_file')
#I must ensure that 'Bob' is in the list of names
if 'Bob' not in args.names:
args.names.append('Bob')
return args
def parse_command_line_args(self):
return self.root_parser.parse_args()
def parse_config_file(self, args):
self.check_args(args)
data = yaml.load(args.config_file)
args.config_file.close()
for key, value in data.items():
if key not in _possible_config_file_keys:
self.root_parser.error("Invalid key '{}' in config file".format(key))
if isinstance(value, str):
value = [value, ]
setattr(args, key, value)
def check_args(self, args):
invalid_keys = [
key for key in vars(args).keys() if key in _possible_config_file_keys
and getattr(args, key)]
if invalid_keys:
self.root_parser.error("Cannot use config-file keys along with config-file")
#For my testing purpose
if __name__ == '__main__':
parser = Parser()
pprint(vars(parser.options))