def reset_parsers(self, usage='', version=None): # configuration file parser self._config_parser = ConfigParser() # command line parser self._optik_parser = OptionParser(usage=usage, version=version) self._optik_parser.options_manager = self
class OptionsManagerMixIn(object): """MixIn to handle a configuration from both a configuration file and command line options """ def __init__(self, usage, config_file=None, version=None, quiet=0): self.config_file = config_file self.reset_parsers(usage, version=version) # list of registered options providers self.options_providers = [] # dictionary assocating option name to checker self._all_options = {} self._short_options = {} self._nocallback_options = {} # verbosity self.quiet = quiet def reset_parsers(self, usage='', version=None): # configuration file parser self._config_parser = ConfigParser() # command line parser self._optik_parser = OptionParser(usage=usage, version=version) self._optik_parser.options_manager = self def register_options_provider(self, provider, own_group=True): """register an options provider""" assert provider.priority <= 0, "provider's priority can't be >= 0" for i in range(len(self.options_providers)): if provider.priority > self.options_providers[i].priority: self.options_providers.insert(i, provider) break else: self.options_providers.append(provider) non_group_spec_options = [option for option in provider.options if not option[1].has_key('group')] groups = getattr(provider, 'option_groups', ()) if own_group: self.add_option_group(provider.name.upper(), provider.__doc__, non_group_spec_options, provider) else: for opt_name, opt_dict in non_group_spec_options: args, opt_dict = self.optik_option(provider, opt_name, opt_dict) self._optik_parser.add_option(*args, **opt_dict) self._all_options[opt_name] = provider for gname, gdoc in groups: goptions = [option for option in provider.options if option[1].get('group') == gname] self.add_option_group(gname, gdoc, goptions, provider) def add_option_group(self, group_name, doc, options, provider): """add an option group including the listed options """ # add section to the config file self._config_parser.add_section(group_name) # add option group to the command line parser if options: group = OptionGroup(self._optik_parser, title=group_name.capitalize()) self._optik_parser.add_option_group(group) # add provider's specific options for opt_name, opt_dict in options: args, opt_dict = self.optik_option(provider, opt_name, opt_dict) group.add_option(*args, **opt_dict) self._all_options[opt_name] = provider def optik_option(self, provider, opt_name, opt_dict): """get our personal option definition and return a suitable form for use with optik/optparse """ opt_dict = copy(opt_dict) if opt_dict.has_key('action'): self._nocallback_options[provider] = opt_name else: opt_dict['action'] = 'callback' opt_dict['callback'] = self.cb_set_provider_option for specific in ('default', 'group', 'inputlevel'): if opt_dict.has_key(specific): del opt_dict[specific] if (OPTPARSE_FORMAT_DEFAULT and specific == 'default' and opt_dict.has_key('help')): opt_dict['help'] += ' [current: %default]' args = ['--' + opt_name] if opt_dict.has_key('short'): self._short_options[opt_dict['short']] = opt_name args.append('-' + opt_dict['short']) del opt_dict['short'] available_keys = set(self._optik_parser.option_class.ATTRS) for key in opt_dict.keys(): if not key in available_keys: opt_dict.pop(key) return args, opt_dict def cb_set_provider_option(self, option, opt_name, value, parser): """optik callback for option setting""" if opt_name.startswith('--'): # remove -- on long option opt_name = opt_name[2:] else: # short option, get its long equivalent opt_name = self._short_options[opt_name[1:]] # trick since we can't set action='store_true' on options if value is None: value = 1 self.global_set_option(opt_name, value) def global_set_option(self, opt_name, value): """set option on the correct option provider""" self._all_options[opt_name].set_option(opt_name, value) def generate_config(self, stream=None, skipsections=()): """write a configuration file according to the current configuration into the given stream or stdout """ stream = stream or sys.stdout printed = False for provider in self.options_providers: default_options = [] sections = {} for section, options in provider.options_by_section(): if section in skipsections: continue options = [(n, d, v) for (n, d, v) in options if d.get('type') is not None] if not options: continue if section is None: section = provider.name doc = provider.__doc__ else: doc = None if printed: print >> stream, '\n' format_section(stream, section.upper(), options, doc) printed = True def generate_manpage(self, pkginfo, section=1, stream=None): """write a man page for the current configuration into the given stream or stdout """ generate_manpage(self._optik_parser, pkginfo, section, stream=stream or sys.stdout) # initialization methods ################################################## def load_provider_defaults(self): """initialize configuration using default values""" for provider in self.options_providers: provider.load_defaults() def load_file_configuration(self, config_file=None): """load the configuration from file""" self.read_config_file(config_file) self.load_config_file() def read_config_file(self, config_file=None): """read the configuration file but do not load it (ie dispatching values to each options provider) """ if config_file is None: config_file = self.config_file if config_file and exists(config_file): self._config_parser.read([config_file]) elif not self.quiet: msg = 'No config file found, using default configuration' print >> sys.stderr, msg return def input_config(self, onlysection=None, inputlevel=0, stream=None): """interactivly get configuration values by asking to the user and generate a configuration file """ if onlysection is not None: onlysection = onlysection.upper() for provider in self.options_providers: for section, option, optdict in provider.all_options(): if onlysection is not None and section != onlysection: continue provider.input_option(option, optdict, inputlevel) # now we can generate the configuration file if stream is not None: self.generate_config(stream) def load_config_file(self): """dispatch values previously read from a configuration file to each options provider) """ parser = self._config_parser for provider in self.options_providers: for section, option, optdict in provider.all_options(): try: value = parser.get(section, option) provider.set_option(option, value, opt_dict=optdict) except (NoSectionError, NoOptionError), ex: continue