149
149
conf.register_opt(rabbit_host_opt, group=rabbit_group)
150
150
conf.register_opt(rabbit_port_opt, group='rabbit')
152
If it no group attributes are required other than the group name, the group
153
need not be explicitly registered e.g.
155
def register_rabbit_opts(conf):
156
# The group will automatically be created, equivalent calling::
157
# conf.register_group(OptGroup(name='rabbit'))
158
conf.register_opt(rabbit_port_opt, group='rabbit')
152
160
If no group is specified, options belong to the 'DEFAULT' section of config
236
This module also contains a global instance of the CommonConfigOpts class
237
in order to support a common usage pattern in OpenStack:
239
from openstack.common import cfg
242
cfg.StrOpt('bind_host' default='0.0.0.0'),
243
cfg.IntOpt('bind_port', default=9292),
247
CONF.register_opts(opts)
249
def start(server, app):
250
server.start(app, CONF.bind_port, CONF.bind_host)
227
254
import collections
291
318
return "duplicate option: %s" % self.opt_name
321
class RequiredOptError(Error):
322
"""Raised if an option is required but no value is supplied by the user."""
324
def __init__(self, opt_name, group=None):
325
self.opt_name = opt_name
329
if self.group is None:
330
return "value required for option: %s" % self.opt_name
332
return "value required for option: %s.%s" % (self.group.name,
294
336
class TemplateSubstitutionError(Error):
295
337
"""Raised if an error occurs substituting a variable in an opt value."""
454
496
def __init__(self, name, dest=None, short=None, default=None,
455
metavar=None, help=None, secret=False):
497
metavar=None, help=None, secret=False, required=False):
456
498
"""Construct an Opt object.
458
500
The only required parameter is the option's name. However, it is
787
def _unregister_opt(self, opt):
788
"""Remove an opt from this group.
790
:param opt: an Opt object
792
if opt.dest in self._opts:
793
del self._opts[opt.dest]
743
795
def _get_optparse_group(self, parser):
744
796
"""Build an optparse.OptionGroup for this group."""
745
797
if self._optparse_group is None:
748
800
return self._optparse_group
803
"""Clear this group's option parsing state."""
804
self._optparse_group = None
751
807
class ParseError(iniparser.ParseError):
752
808
def __init__(self, msg, lineno, line, filename):
821
877
the values of options.
829
default_config_files=None):
830
"""Construct a ConfigOpts object.
832
Automatically registers the --config-file option with either a supplied
833
list of default config files, or a list from find_config_files().
835
:param project: the toplevel project name, used to locate config files
836
:param prog: the name of the program (defaults to sys.argv[0] basename)
837
:param version: the program version (for --version)
838
:param usage: a usage string (%prog will be expanded)
839
:param default_config_files: config files to use by default
881
"""Construct a ConfigOpts object."""
882
self._opts = {} # dict of dicts of (opt:, override:, default:)
888
self._cli_values = {}
890
self._config_opts = []
891
self._disable_interspersed_args = False
893
def _setup(self, project, prog, version, usage, default_config_files):
894
"""Initialize a ConfigOpts object for option parsing."""
842
896
prog = os.path.basename(sys.argv[0])
844
898
if default_config_files is None:
845
899
default_config_files = find_config_files(project, prog)
847
self.project = project
849
self.version = version
851
self.default_config_files = default_config_files
853
self._opts = {} # dict of dicts of (opt:, override:, default:)
857
self._cli_values = {}
859
self._oparser = optparse.OptionParser(prog=self.prog,
860
version=self.version,
867
MultiStrOpt('config-file',
868
default=self.default_config_files,
870
help='Path to a config file to use. Multiple config '
871
'files can be specified, with values in later '
872
'files taking precedence. The default files '
874
(self.default_config_files, )),
901
self._oparser = optparse.OptionParser(prog=prog,
904
if self._disable_interspersed_args:
905
self._oparser.disable_interspersed_args()
907
self._config_opts = [
908
MultiStrOpt('config-file',
909
default=default_config_files,
911
help='Path to a config file to use. Multiple config '
912
'files can be specified, with values in later '
913
'files taking precedence. The default files '
914
' used are: %s' % (default_config_files, )),
875
915
StrOpt('config-dir',
877
917
help='Path to a config directory to pull *.conf '
881
921
'the file(s), if any, specified via --config-file, '
882
922
'hence over-ridden options in the directory take '
885
self.register_cli_opts(opts)
925
self.register_cli_opts(self._config_opts)
927
self.project = project
929
self.version = version
931
self.default_config_files = default_config_files
887
933
def __clear_cache(f):
888
934
@functools.wraps(f)
903
955
The object may be called multiple times, each time causing the previous
904
956
set of values to be overwritten.
958
Automatically registers the --config-file option with either a supplied
959
list of default config files, or a list from find_config_files().
906
961
If the --config-dir option is set, any *.conf files from this
907
962
directory are pulled in, after all the file(s) specified by the
908
963
--config-file option.
910
:params args: command line arguments (defaults to sys.argv[1:])
965
:param args: command line arguments (defaults to sys.argv[1:])
966
:param project: the toplevel project name, used to locate config files
967
:param prog: the name of the program (defaults to sys.argv[0] basename)
968
:param version: the program version (for --version)
969
:param usage: a usage string (%prog will be expanded)
970
:param default_config_files: config files to use by default
911
971
:returns: the list of arguments left over after parsing options
912
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError
972
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError,
973
RequiredOptError, DuplicateOptError
918
(values, args) = self._oparser.parse_args(self._args)
920
self._cli_values = vars(values)
922
def _list_config_dir():
923
return sorted(glob.glob(os.path.join(self.config_dir, '*.conf')))
925
from_file = list(self.config_file)
927
from_dir = _list_config_dir() if self.config_dir else []
929
self._parse_config_files(from_file + from_dir)
977
self._setup(project, prog, version, usage, default_config_files)
979
self._cli_values, leftovers = self._parse_cli_opts(args)
981
self._parse_config_files()
983
self._check_required_opts()
933
987
def __getattr__(self, name):
934
988
"""Look up an option value and perform string substitution.
956
1010
"""Return the number of options and option groups."""
957
1011
return len(self._opts) + len(self._groups)
960
1013
def reset(self):
961
"""Reset the state of the object to before it was called."""
1014
"""Clear the object state and unset overrides and defaults."""
1015
self._unset_defaults_and_overrides()
1020
"""Clear the state of the object to before it was called."""
962
1021
self._args = None
963
self._cli_values = None
1022
self._cli_values.clear()
1023
self._oparser = None
964
1024
self._cparser = None
1025
self.unregister_opts(self._config_opts)
1026
for group in self._groups.values():
967
1030
def register_opt(self, opt, group=None):
1008
1071
if self._args is not None:
1009
1072
raise ArgsAlreadyParsedError("cannot register CLI option")
1011
if not self.register_opt(opt, group, clear_cache=False):
1014
if group is not None:
1015
group = self._get_group(group)
1017
opt._add_to_cli(self._oparser, group)
1074
return self.register_opt(opt, group, clear_cache=False)
1022
1077
def register_cli_opts(self, opts, group=None):
1038
1093
self._groups[group.name] = copy.copy(group)
1096
def unregister_opt(self, opt, group=None):
1097
"""Unregister an option.
1099
:param opt: an Opt object
1100
:param group: an optional OptGroup object or group name
1101
:raises: ArgsAlreadyParsedError, NoSuchGroupError
1103
if self._args is not None:
1104
raise ArgsAlreadyParsedError("reset before unregistering options")
1106
if group is not None:
1107
self._get_group(group)._unregister_opt(opt)
1108
elif opt.dest in self._opts:
1109
del self._opts[opt.dest]
1112
def unregister_opts(self, opts, group=None):
1113
"""Unregister multiple CLI option schemas at once."""
1115
self.unregister_opt(opt, group, clear_cache=False)
1041
1118
def set_override(self, name, override, group=None):
1042
1119
"""Override an opt value.
1067
1144
opt_info = self._get_opt_info(name, group)
1068
1145
opt_info['default'] = default
1147
def _all_opt_infos(self):
1148
"""A generator function for iteration opt infos."""
1149
for info in self._opts.values():
1151
for group in self._groups.values():
1152
for info in group._opts.values():
1155
def _all_opts(self):
1156
"""A generator function for iteration opts."""
1157
for info, group in self._all_opt_infos():
1158
yield info['opt'], group
1160
def _unset_defaults_and_overrides(self):
1161
"""Unset any default or override on all options."""
1162
for info, group in self._all_opt_infos():
1163
info['default'] = None
1164
info['override'] = None
1070
1166
def disable_interspersed_args(self):
1071
1167
"""Set parsing to stop on the first non-option.
1085
1181
i.e. argument parsing is stopped at the first non-option argument.
1087
self._oparser.disable_interspersed_args()
1183
self._disable_interspersed_args = True
1089
1185
def enable_interspersed_args(self):
1090
1186
"""Set parsing to not stop on the first non-option.
1092
1188
This it the default behaviour."""
1093
self._oparser.enable_interspersed_args()
1189
self._disable_interspersed_args = False
1095
1191
def find_file(self, name):
1096
1192
"""Locate a file located alongside the config files.
1188
1284
return self.GroupAttr(self, self._get_group(name))
1190
1286
info = self._get_opt_info(name, group)
1191
default, opt, override = map(lambda k: info[k], sorted(info.keys()))
1287
default, opt, override = [info[k] for k in sorted(info.keys())]
1193
1289
if override is not None:
1194
1290
return override
1252
1348
the API have access to.
1254
1350
:param group_or_name: the group's name or the OptGroup object itself
1351
:param autocreate: whether to auto-create the group if it's not found
1255
1352
:raises: NoSuchGroupError
1257
if isinstance(group_or_name, OptGroup):
1258
group_name = group_or_name.name
1260
group_name = group_or_name
1354
group = group_or_name if isinstance(group_or_name, OptGroup) else None
1355
group_name = group.name if group else group_or_name
1262
1357
if not group_name in self._groups:
1263
raise NoSuchGroupError(group_name)
1358
if not group is None or not autocreate:
1359
raise NoSuchGroupError(group_name)
1361
self.register_group(OptGroup(name=group_name))
1265
1363
return self._groups[group_name]
1283
1381
return opts[opt_name]
1285
def _parse_config_files(self, config_files):
1286
"""Parse the supplied configuration files.
1383
def _parse_config_files(self):
1384
"""Parse the config files from --config-file and --config-dir.
1288
1386
:raises: ConfigFilesNotFoundError, ConfigFileParseError
1388
config_files = list(self.config_file)
1391
config_dir_glob = os.path.join(self.config_dir, '*.conf')
1392
config_files += sorted(glob.glob(config_dir_glob))
1290
1394
self._cparser = MultiConfigParser()
1298
1402
not_read_ok = filter(lambda f: f not in read_ok, config_files)
1299
1403
raise ConfigFilesNotFoundError(not_read_ok)
1405
def _check_required_opts(self):
1406
"""Check that all opts marked as required have values specified.
1408
:raises: RequiredOptError
1410
for info, group in self._all_opt_infos():
1411
default, opt, override = [info[k] for k in sorted(info.keys())]
1414
if (default is not None or override is not None):
1417
if self._get(opt.name, group) is None:
1418
raise RequiredOptError(opt.name, group)
1420
def _parse_cli_opts(self, args):
1421
"""Parse command line options.
1423
Initializes the command line option parser and parses the supplied
1424
command line arguments.
1426
:param args: the command line arguments
1427
:returns: a dict of parsed option values
1428
:raises: SystemExit, DuplicateOptError
1433
for opt, group in self._all_opts():
1434
opt._add_to_cli(self._oparser, group)
1436
values, leftovers = self._oparser.parse_args(args)
1438
return vars(values), leftovers
1301
1440
class GroupAttr(collections.Mapping):
1410
1549
StrOpt('syslog-log-facility',
1411
1550
default='LOG_USER',
1412
1551
help='syslog facility to receive log lines')
1415
def __init__(self, **kwargs):
1416
super(CommonConfigOpts, self).__init__(**kwargs)
1555
super(CommonConfigOpts, self).__init__()
1417
1556
self.register_cli_opts(self.common_cli_opts)
1418
1557
self.register_cli_opts(self.logging_cli_opts)
1560
CONF = CommonConfigOpts()