Hello community, here is the log from the commit of package python-oslo.config for openSUSE:Factory checked in at 2015-07-12 22:52:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-oslo.config (Old) and /work/SRC/openSUSE:Factory/.python-oslo.config.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-oslo.config" Changes: -------- --- /work/SRC/openSUSE:Factory/python-oslo.config/python-oslo.config.changes 2015-05-02 21:35:13.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-oslo.config.new/python-oslo.config.changes 2015-07-12 22:52:29.000000000 +0200 @@ -1,0 +2,36 @@ +Mon Mar 30 05:59:51 UTC 2015 - tbecht...@suse.com + +- update to 1.9.3: + * Switch to non-namespaced module imports + +------------------------------------------------------------------- +Tue Mar 10 10:09:49 UTC 2015 - tbecht...@suse.com + +- update to 1.9.2: + * print better message when choices has an empty string + * None in config choices breaks oslo-config-generator + * Generate help text indicating possible values + * fix bug link in readme + * Add ability to deprecate opts for removal + * Typo in StrOpt docstring: Integer to String + * Add exception handling for entry points + +------------------------------------------------------------------- +Tue Feb 24 08:29:05 UTC 2015 - tbecht...@suse.com + +- update to 1.7.0: + * Updated from global requirements + * Log a warning when deprecated opts are used + * Do not import our namespace package + * Fixes deprecation warning for oslo.config in cfg.py + * Clear up MultiStrOpt and related documentation + * Add a list_all_sections method to ConfigOpts + * Better check for integer range to account for 0 + * Reword DeprecatedOpt docstring + * Support i18n messages in config generator + * Fix of wrong cli opts unregistration +- Cleanup BuildRequires. SLES 11 is no longer a build target +- Add python-oslo.i18n as BuildRequires for tests +- Disable testrun for now + +------------------------------------------------------------------- Old: ---- oslo.config-1.6.0.tar.gz New: ---- oslo.config-1.9.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-oslo.config.spec ++++++ --- /var/tmp/diff_new_pack.z2HKgP/_old 2015-07-12 22:52:29.000000000 +0200 +++ /var/tmp/diff_new_pack.z2HKgP/_new 2015-07-12 22:52:29.000000000 +0200 @@ -17,7 +17,7 @@ Name: python-oslo.config -Version: 1.6.0 +Version: 1.9.3 Release: 0 Url: https://launchpad.net/oslo/ Summary: OpenStack configuration API @@ -31,14 +31,10 @@ BuildRequires: python-oslosphinx BuildRequires: python-pbr # Test requirements: -#BuildRequires: python-coverage >= 3.6 -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -BuildRequires: python-argparse -BuildRequires: python-discover -%endif BuildRequires: python-fixtures >= 0.3.14 BuildRequires: python-mock >= 1.0 BuildRequires: python-netaddr +BuildRequires: python-oslo.i18n >= 1.3.0 BuildRequires: python-oslotest >= 1.2.0 BuildRequires: python-python-subunit >= 0.0.18 BuildRequires: python-six @@ -48,16 +44,11 @@ BuildRequires: python-testtools >= 0.9.36 Requires: python-netaddr >= 0.7.12 Requires: python-pbr >= 0.6 -Requires: python-six >= 1.7 -Requires: python-stevedore >= 1.1 +Requires: python-six >= 1.9.0 +Requires: python-stevedore >= 1.1.0 Provides: python-oslo-config = 2013.2 Obsoletes: python-oslo-config < 2013.2 -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -Requires: python-argparse -%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%else BuildArch: noarch -%endif Provides: %{name}-test = %{version} Obsoletes: %{name}-test <= %{version} @@ -92,9 +83,9 @@ # has one in $BUILDROOT. But the former takes precedence since %{python_sitelib} is always last sys.path. Thus # tests can never find the oslo.config module. Obviously PYTHONPATH alone won't help either. But distro-boys # have bigger balls than stackers and fix themselves a custom load order with the magic '-S' flag: -export PYTHONPATH="%{python_sitelib}:%{buildroot}%{python_sitelib}" -export PYTHON="python -S" -testr init && testr run --parallel +#export PYTHONPATH="%{buildroot}%{python_sitelib}:%{python_sitelib}" +#export PYTHON="python -S" +#testr init && testr run --parallel %files %defattr(-,root,root,-) ++++++ oslo.config-1.6.0.tar.gz -> oslo.config-1.9.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/AUTHORS new/oslo.config-1.9.3/AUTHORS --- old/oslo.config-1.6.0/AUTHORS 2015-01-05 19:32:55.000000000 +0100 +++ new/oslo.config-1.9.3/AUTHORS 2015-03-12 17:23:48.000000000 +0100 @@ -14,9 +14,11 @@ David Ripton <drip...@redhat.com> David Stanek <dsta...@dstanek.com> Dirk Mueller <d...@dmllr.de> +Doug Chivers <doug.chiv...@hp.com> Doug Hellmann <doug.hellm...@dreamhost.com> Doug Hellmann <d...@doughellmann.com> Eoghan Glynn <egl...@redhat.com> +Eric Brown <bro...@vmware.com> Eric Guo <eric....@easystack.cn> Fengqian.Gao <fengqian....@intel.com> Flaper Fesp <flape...@gmail.com> @@ -27,6 +29,7 @@ Jakub Libosvar <libos...@redhat.com> James Carey <jeca...@us.ibm.com> James E. Blair <jebl...@openstack.org> +Jamie Lennox <jamielen...@redhat.com> Jason Kölker <ja...@koelker.net> Jay S. Bryant <jsbry...@us.ibm.com> Jeremy Stanley <fu...@yuggoth.org> @@ -53,6 +56,7 @@ Petr Blaho <petrbl...@gmail.com> Radomir Dopieralski <openst...@sheep.art.pl> Rick Harris <rconradhar...@gmail.com> +Rushi Agrawal <rushi....@gmail.com> Russell Bryant <rbry...@redhat.com> Ryan Moore <ryan.mo...@hp.com> Sascha Peilicke <sasc...@gmx.de> @@ -72,3 +76,4 @@ llg8212 <lilin...@huawei.com> lzyeval <lzye...@gmail.com> skudriashev <skudrias...@griddynamics.com> +vponomaryov <vponomar...@mirantis.com> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/ChangeLog new/oslo.config-1.9.3/ChangeLog --- old/oslo.config-1.6.0/ChangeLog 2015-01-05 19:32:55.000000000 +0100 +++ new/oslo.config-1.9.3/ChangeLog 2015-03-12 17:23:48.000000000 +0100 @@ -1,6 +1,53 @@ CHANGES ======= +1.9.3 +----- + +* Switch to non-namespaced module imports + +1.9.2 +----- + +* print better message when choices has an empty string +* None in config choices breaks oslo-config-generator + +1.9.1 +----- + +* Generate help text indicating possible values + +1.9.0 +----- + +* fix bug link in readme +* Add ability to deprecate opts for removal +* Typo in StrOpt docstring: Integer to String + +1.8.0 +----- + +* Add exception handling for entry points + +1.7.0 +----- + +* Updated from global requirements +* Add expose_opt to CfgFilter +* Log a warning when deprecated opts are used +* Do not import our namespace package +* Fixes deprecation warning for oslo.config in cfg.py + +1.6.1 +----- + +* Clear up MultiStrOpt and related documentation +* Add a list_all_sections method to ConfigOpts +* Better check for integer range to account for 0 +* Reword DeprecatedOpt docstring +* Support i18n messages in config generator +* Fix of wrong cli opts unregistration + 1.6.0 ----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/PKG-INFO new/oslo.config-1.9.3/PKG-INFO --- old/oslo.config-1.6.0/PKG-INFO 2015-01-05 19:32:55.000000000 +0100 +++ new/oslo.config-1.9.3/PKG-INFO 2015-03-12 17:23:49.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: oslo.config -Version: 1.6.0 +Version: 1.9.3 Summary: Oslo Configuration API Home-page: https://launchpad.net/oslo Author: OpenStack @@ -16,7 +16,7 @@ * License: Apache License, Version 2.0 * Documentation: http://docs.openstack.org/developer/oslo.config * Source: http://git.openstack.org/cgit/openstack/oslo.config - * Bugs: http://bugs.launchpad.net/oslo + * Bugs: http://bugs.launchpad.net/oslo.config Platform: UNKNOWN diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/README.rst new/oslo.config-1.9.3/README.rst --- old/oslo.config-1.6.0/README.rst 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/README.rst 2015-03-12 17:23:28.000000000 +0100 @@ -8,4 +8,4 @@ * License: Apache License, Version 2.0 * Documentation: http://docs.openstack.org/developer/oslo.config * Source: http://git.openstack.org/cgit/openstack/oslo.config -* Bugs: http://bugs.launchpad.net/oslo +* Bugs: http://bugs.launchpad.net/oslo.config diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/doc/source/opts.rst new/oslo.config-1.9.3/doc/source/opts.rst --- old/oslo.config-1.6.0/doc/source/opts.rst 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/doc/source/opts.rst 2015-03-12 17:23:28.000000000 +0100 @@ -11,6 +11,7 @@ .. autoclass:: FloatOpt .. autoclass:: ListOpt .. autoclass:: DictOpt +.. autoclass:: MultiOpt .. autoclass:: MultiStrOpt .. autoclass:: IPOpt .. autoclass:: DeprecatedOpt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo.config.egg-info/PKG-INFO new/oslo.config-1.9.3/oslo.config.egg-info/PKG-INFO --- old/oslo.config-1.6.0/oslo.config.egg-info/PKG-INFO 2015-01-05 19:32:55.000000000 +0100 +++ new/oslo.config-1.9.3/oslo.config.egg-info/PKG-INFO 2015-03-12 17:23:48.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: oslo.config -Version: 1.6.0 +Version: 1.9.3 Summary: Oslo Configuration API Home-page: https://launchpad.net/oslo Author: OpenStack @@ -16,7 +16,7 @@ * License: Apache License, Version 2.0 * Documentation: http://docs.openstack.org/developer/oslo.config * Source: http://git.openstack.org/cgit/openstack/oslo.config - * Bugs: http://bugs.launchpad.net/oslo + * Bugs: http://bugs.launchpad.net/oslo.config Platform: UNKNOWN diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo.config.egg-info/pbr.json new/oslo.config-1.9.3/oslo.config.egg-info/pbr.json --- old/oslo.config-1.6.0/oslo.config.egg-info/pbr.json 2015-01-05 19:32:55.000000000 +0100 +++ new/oslo.config-1.9.3/oslo.config.egg-info/pbr.json 2015-03-12 17:23:48.000000000 +0100 @@ -1 +1 @@ -{"git_version": "99e530e", "is_release": true} \ No newline at end of file +{"is_release": true, "git_version": "3c51838"} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo.config.egg-info/requires.txt new/oslo.config-1.9.3/oslo.config.egg-info/requires.txt --- old/oslo.config-1.6.0/oslo.config.egg-info/requires.txt 2015-01-05 19:32:55.000000000 +0100 +++ new/oslo.config-1.9.3/oslo.config.egg-info/requires.txt 2015-03-12 17:23:48.000000000 +0100 @@ -1,5 +1,5 @@ pbr>=0.6,!=0.7,<1.0 argparse netaddr>=0.7.12 -six>=1.7.0 +six>=1.9.0 stevedore>=1.1.0 # Apache-2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/cfg.py new/oslo.config-1.9.3/oslo_config/cfg.py --- old/oslo.config-1.6.0/oslo_config/cfg.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/cfg.py 2015-03-12 17:23:28.000000000 +0100 @@ -13,15 +13,15 @@ # under the License. r""" -Configuration options which may be set on the command line or in config files. +Configuration options may be set on the command line or in config files. -The schema for each option is defined using the Opt class or its sub-classes, -for example: +The schema for each option is defined using the +:class:`Opt` class or its sub-classes, for example: :: - from oslo.config import cfg - from oslo.config import types + from oslo_config import cfg + from oslo_config import types PortType = types.Integer(1, 65535) @@ -38,13 +38,14 @@ Option Types ------------ -Options can have arbitrary types, you just need to pass type constructor -to Opt. Type constructor is a callable object that takes a string and returns -value of particular type or raises ValueError if given string can't be -converted to that type. - -There are predefined types: strings, integers, floats, booleans, lists, -'multi strings' and 'key/value pairs' (dictionary) :: +Options can have arbitrary types via the ``type`` constructor to +``Opt``. The type constructor is a callable object that takes a string and +either returns a value of that particular type or raises ValueError if +the value can not be converted. + +There are predefined types in :class:`oslo_config.cfg` : strings, +integers, floats, booleans, lists, 'multi strings' and 'key/value +pairs' (dictionary) :: enabled_apis_opt = cfg.ListOpt('enabled_apis', default=['ec2', 'osapi_compute'], @@ -127,7 +128,7 @@ self.register_cli_opts(opts) Option values are parsed from any supplied config files using -oslo.config.iniparser. If none are specified, a default set is used +oslo_config.iniparser. If none are specified, a default set is used for example glance-api.conf and glance-common.conf:: glance-api.conf: @@ -270,7 +271,7 @@ This module also contains a global instance of the ConfigOpts class in order to support a common usage pattern in OpenStack:: - from oslo.config import cfg + from oslo_config import cfg opts = [ cfg.StrOpt('bind_host', default='0.0.0.0'), @@ -330,8 +331,8 @@ import six from six import moves -from oslo.config import iniparser -from oslo.config import types +from oslo_config import iniparser +from oslo_config import types LOG = logging.getLogger(__name__) @@ -597,8 +598,9 @@ name: the name of the option, which may include hyphens type: - a callable object that takes string and returns - converted and validated value + a callable object that takes string and returns converted and + validated value. Default types are available from + :class:`oslo_config.types` dest: the (hyphen-less) ConfigOpts property which contains the option value short: @@ -612,7 +614,7 @@ metavar: the name shown as the argument to a CLI option in --help output help: - an string explaining how the options value is used + a string explaining how the option's value is used """ multi = False @@ -620,7 +622,8 @@ default=None, positional=False, metavar=None, help=None, secret=False, required=False, deprecated_name=None, deprecated_group=None, - deprecated_opts=None, sample_default=None): + deprecated_opts=None, sample_default=None, + deprecated_for_removal=False): """Construct an Opt object. The only required parameter is the option's name. However, it is @@ -641,6 +644,8 @@ :param deprecated_group: the group containing a deprecated alias :param deprecated_opts: array of DeprecatedOpt(s) :param sample_default: a default string for sample config files + :param deprecated_for_removal: indicates whether this opt is planned + for removal in a future release """ if name.startswith('_'): raise ValueError('illegal name %s with prefix _' % (name,)) @@ -665,6 +670,8 @@ self.help = help self.secret = secret self.required = required + self.deprecated_for_removal = deprecated_for_removal + self._logged_deprecation = False if deprecated_name is not None: deprecated_name = deprecated_name.replace('-', '_') @@ -717,7 +724,16 @@ names.append((dgroup if dgroup else group_name, dname if dname else self.dest)) - return namespace._get_value(names, self.multi, self.positional) + value = namespace._get_value(names, self.multi, self.positional) + # The previous line will raise a KeyError if no value is set in the + # config file, so we'll only log deprecations for set options. + if self.deprecated_for_removal and not self._logged_deprecation: + self._logged_deprecation = True + pretty_group = group_name or 'DEFAULT' + LOG.warning('Option "%s" from group "%s" is deprecated for ' + 'removal. Its value may be silently ignored in the ' + 'future.', self.dest, pretty_group) + return value def _add_to_cli(self, parser, group=None): """Makes the option available in the command line interface. @@ -855,31 +871,47 @@ Here's how you can use it:: - oldopts = [cfg.DeprecatedOpt('oldfoo', group='oldgroup'), - cfg.DeprecatedOpt('oldfoo2', group='oldgroup2')] - cfg.CONF.register_group(cfg.OptGroup('blaa')) - cfg.CONF.register_opt(cfg.StrOpt('foo', deprecated_opts=oldopts), - group='blaa') + oldopts = [cfg.DeprecatedOpt('oldopt1', group='group1'), + cfg.DeprecatedOpt('oldopt2', group='group2')] + cfg.CONF.register_group(cfg.OptGroup('group1')) + cfg.CONF.register_opt(cfg.StrOpt('newopt', deprecated_opts=oldopts), + group='group1') + + For options which have a single value (like in the example above), + if the new option is present ("[group1]/newopt" above), it will override + any deprecated options present ("[group1]/oldopt1" and "[group2]/oldopt2" + above). + + If no group is specified for a DeprecatedOpt option (i.e. the group is + None), lookup will happen within the same group the new option is in. + For example, if no group was specified for the second option 'oldopt2' in + oldopts list: + + oldopts = [cfg.DeprecatedOpt('oldopt1', group='group1'), + cfg.DeprecatedOpt('oldopt2')] + cfg.CONF.register_group(cfg.OptGroup('group1')) + cfg.CONF.register_opt(cfg.StrOpt('newopt', deprecated_opts=oldopts), + group='group1') + + then lookup for that option will happen in group 'group1'. + + If the new option is not present and multiple deprecated options are + present, the option corresponding to the first element of deprecated_opts + will be chosen. Multi-value options will return all new and deprecated - options. For single options, if the new option is present - ("[blaa]/foo" above) it will override any deprecated options - present. If the new option is not present and multiple - deprecated options are present, the option corresponding to - the first element of deprecated_opts will be chosen. - - If group is None, the DeprecatedOpt lookup will happen within the same - group the new option is in. For example:: - - oldopts = [cfg.DeprecatedOpt('oldfoo'), - cfg.DeprecatedOpt('oldfoo2', group='DEFAULT')] - - cfg.CONF.register_group(cfg.OptGroup('blaa')) - cfg.CONF.register_opt(cfg.StrOpt('foo', deprecated_opts=oldopts), - group='blaa') + options. So if we have a multi-value option "[group1]/opt1" whose + deprecated option is "[group2]/opt2", and the conf file has both these + options specified like so:: + + [group1] + opt1=val10,val11 + + [group2] + opt2=val21,val22 - In the example above, `oldfoo` will be looked up in the `blaa` group and - `oldfoo2` in the `DEFAULT` group. + Then the value of "[group1]/opt1" will be ['val11', 'val12', 'val21', + 'val22']. """ def __init__(self, name, group=None): @@ -902,7 +934,11 @@ class StrOpt(Opt): - """Option with String type (for backward compatibility). + """Option with String type + + Option with ``type`` :class:`oslo_config.types.String` + + `Kept for backward-compatibility with options not using Opt directly`. :param choices: Optional sequence of valid values. """ @@ -969,7 +1005,12 @@ class IntOpt(Opt): - """Opt with Integer type (for backward compatibility).""" + """Option with Integer type + + Option with ``type`` :class:`oslo_config.types.Integer` + + `Kept for backward-compatibility with options not using Opt directly`. + """ def __init__(self, name, **kwargs): super(IntOpt, self).__init__(name, type=types.Integer(), **kwargs) @@ -977,7 +1018,12 @@ class FloatOpt(Opt): - """Opt with Float type (for backward compatibility).""" + """Option with Float type + + Option with ``type`` :class:`oslo_config.types.Float` + + `Kept for backward-communicability with options not using Opt directly`. + """ def __init__(self, name, **kwargs): super(FloatOpt, self).__init__(name, type=types.Float(), **kwargs) @@ -985,7 +1031,12 @@ class ListOpt(Opt): - """Opt with List(String) type (for backward compatibility).""" + """Option with List(String) type + + Option with ``type`` :class:`oslo_config.types.List` + + `Kept for backward-compatibility with options not using Opt directly`. + """ def __init__(self, name, **kwargs): super(ListOpt, self).__init__(name, type=types.List(), **kwargs) @@ -993,7 +1044,12 @@ class DictOpt(Opt): - """Opt with Dict(String) type (for backward compatibility).""" + """Option with Dict(String) type + + Option with ``type`` :class:`oslo_config.types.Dict` + + `Kept for backward-compatibility with options not using Opt directly`. + """ def __init__(self, name, **kwargs): super(DictOpt, self).__init__(name, type=types.Dict(), **kwargs) @@ -1001,7 +1057,13 @@ class IPOpt(Opt): - """Opt with IPAddress type (either IPv4, IPv6 or both).""" + """Opt with IPAddress type + + Option with ``type`` :class:`oslo_config.types.IPAddress` + + :param version: one of either ``4``, ``6``, or ``None`` to specify + either version. + """ def __init__(self, name, version=None, **kwargs): super(IPOpt, self).__init__(name, type=types.IPAddress(version), @@ -1014,6 +1076,19 @@ Multi opt values are typed opts which may be specified multiple times. The opt value is a list containing all the values specified. + + :param name: Name of the config option + :param item_type: Type of items (see :class:`oslo_config.types`) + + For example:: + + cfg.MultiOpt('foo', + item_type=types.Integer(), + default=None, + help="Multiple foo option") + + The command line ``--foo=1 --foo=2`` would result in ``cfg.CONF.foo`` + containing ``[1,2]`` """ multi = True @@ -1032,7 +1107,15 @@ class MultiStrOpt(MultiOpt): - """Multi opt with MultiString item type (for backward compatibility).""" + """MultiOpt with a MultiString ``item_type``. + + MultiOpt with a default :class:`oslo_config.types.MultiString` item + type. + + `Kept for backwards-compatibility for options that do not use + MultiOpt directly`. + + """ def __init__(self, name, **kwargs): super(MultiStrOpt, self).__init__(name, @@ -1347,9 +1430,13 @@ class MultiConfigParser(object): + _deprecated_opt_message = ('Option "%s" from group "%s" is deprecated. ' + 'Use option "%s" from group "%s".') + def __init__(self): self.parsed = [] self._normalized = [] + self._emitted_deprecations = set() def read(self, config_files): read_ok = [] @@ -1401,6 +1488,8 @@ if section not in sections: continue if name in sections[section]: + self._check_deprecated((section, name), names[0], + names[1:]) val = sections[section][name] if multi: rvalue = val + rvalue @@ -1410,6 +1499,32 @@ return rvalue raise KeyError + def _check_deprecated(self, name, current, deprecated): + """Check for usage of deprecated names. + + :param name: A tuple of the form (group, name) representing the group + and name where an opt value was found. + :param current: A tuple of the form (group, name) representing the + current name for an option. + :param deprecated: A list of tuples with the same format as the name + param which represent any deprecated names for an option. + If the name param matches any entries in this list a + deprecation warning will be logged. + """ + # Opts in the DEFAULT group may come in with a group name of either + # 'DEFAULT' or None. Force them all to 'DEFAULT' since that's a more + # user-friendly form. + deprecated_names = set((g or 'DEFAULT', n) for (g, n) in deprecated) + name = (name[0] or 'DEFAULT', name[1]) + if name in deprecated_names and name not in self._emitted_deprecations: + self._emitted_deprecations.add(name) + current = (current[0] or 'DEFAULT', current[1]) + # NOTE(bnemec): Not using versionutils for this to avoid a + # circular dependency between oslo.config and whatever library + # versionutils ends up in. + LOG.warning(self._deprecated_opt_message, name[1], + name[0], current[1], current[0]) + class _Namespace(argparse.Namespace): @@ -1883,8 +1998,15 @@ if self._args is not None: raise ArgsAlreadyParsedError("reset before unregistering options") - if {'opt': opt, 'group': group} in self._cli_opts: - self._cli_opts.remove({'opt': opt, 'group': group}) + remitem = None + for item in self._cli_opts: + if (item['opt'].dest == opt.dest and + (group is None or + self._get_group(group).name == item['group'].name)): + remitem = item + break + if remitem is not None: + self._cli_opts.remove(remitem) if group is not None: self._get_group(group)._unregister_opt(opt) @@ -2363,6 +2485,16 @@ self._namespace = namespace return True + def list_all_sections(self): + """List all sections from the configuration. + + Returns an iterator over all section names found in the + configuration files, whether declared beforehand or not. + """ + for sections in self._namespace._parser.parsed: + for section in sections: + yield section + class GroupAttr(collections.Mapping): """Helper class. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/cfgfilter.py new/oslo.config-1.9.3/oslo_config/cfgfilter.py --- old/oslo.config-1.6.0/oslo_config/cfgfilter.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/cfgfilter.py 2015-03-12 17:23:28.000000000 +0100 @@ -13,7 +13,7 @@ # under the License. r""" -There are two use cases for the ConfigFilter class: +There are three use cases for the ConfigFilter class: 1. Help enforce that a given module does not access options registered by another module, without first declaring those cross-module @@ -22,6 +22,8 @@ 2. Prevent private configuration opts from being visible to modules other than the one which registered it. +3. Limit the options on a Cfg object that can be accessed. + Cross-Module Option Dependencies -------------------------------- @@ -77,8 +79,8 @@ from __future__ import print_function - from oslo.config.cfg import * - from oslo.config.cfgfilter import * + from oslo_config.cfg import * + from oslo_config.cfgfilter import * class Widget(object): @@ -96,12 +98,37 @@ print(widget.foo) print(conf.foo) # raises NoSuchOptError + +Limited Configuration Options +----------------------------- + +It may be required that when passing a CONF object to other functions we want +to filter that the receiving code is only able to access a restricted subset +of the options that are available on the CONF object. This is essentially a +more general case of the Private Configuration Options and Cross-Module Options +whereby we expose an option that is already present on the underlying CONF +object without providing any means to load it if not present. + +So given a CONF object with options defined:: + + CONF.register_opt(StrOpt('foo')) + CONF.register_opt(StrOpt('bar')) + +we can expose options such that only those options are present:: + + restricted_conf = CfgFilter(CONF) + restricted_conf.expose_opt('foo') + + print(restricted_conf.foo) + print(restricted_conf.bar) # raises NoSuchOptError + + """ import collections import itertools -from oslo.config import cfg +from oslo_config import cfg class ConfigFilter(collections.Mapping): @@ -273,6 +300,28 @@ self._imported_groups[group_name] = group return group + def expose_opt(self, opt_name, group=None): + """Expose an option from the underlying conf object. + + This allows an object that has already been imported or used from the + base conf object to be seen from the filter object. + + :param opt_name: the name/dest of the opt + :param group: an option OptGroup object or group name + """ + self._import_opt(opt_name, group) + + def expose_group(self, group): + """Expose all option from a group in the underlying conf object. + + This allows an object that has already been imported or used from the + base conf object to be seen from the filter object. + + :param group: an option OptGroup object or group name + """ + group = self._import_group(group) + group._all_opts = True + class GroupAttr(collections.Mapping): """Helper class to wrap a group object. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/fixture.py new/oslo.config-1.9.3/oslo_config/fixture.py --- old/oslo.config-1.6.0/oslo_config/fixture.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/fixture.py 2015-03-12 17:23:28.000000000 +0100 @@ -18,7 +18,7 @@ import fixtures import six -from oslo.config import cfg +from oslo_config import cfg class Config(fixtures.Fixture): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/generator.py new/oslo.config-1.9.3/oslo_config/generator.py --- old/oslo.config-1.6.0/oslo_config/generator.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/generator.py 2015-03-12 17:23:28.000000000 +0100 @@ -109,8 +109,9 @@ import textwrap import pkg_resources +import six -from oslo.config import cfg +from oslo_config import cfg import stevedore.named # noqa LOG = logging.getLogger(__name__) @@ -176,6 +177,13 @@ lines = ['# ' + help_text + '\n'] return lines + def _get_choice_text(self, choice): + if choice is None: + return '<None>' + elif choice == '': + return "''" + return six.text_type(choice) + def format(self, opt): """Format a description of an option to the output file. @@ -186,9 +194,18 @@ opt_type = self._TYPE_DESCRIPTIONS.get(type(opt), 'unknown type') - help_text = u'%s(%s)' % (opt.help + ' ' if opt.help else '', opt_type) + if opt.help: + help_text = u'%s (%s)' % (opt.help, + opt_type) + else: + help_text = u'(%s)' % opt_type lines = self._format_help(help_text) + if getattr(opt.type, 'choices', None): + choices_text = ', '.join([self._get_choice_text(choice) + for choice in opt.type.choices]) + lines.append('# Allowed values: %s\n' % choices_text) + for d in opt.deprecated_opts: lines.append('# Deprecated group/name - [%s]/%s\n' % (d.group or 'DEFAULT', d.name or opt.dest)) @@ -253,12 +270,18 @@ :param namespaces: a list of namespaces registered under 'oslo.config.opts' :returns: a list of (namespace, [(group, [opt_1, opt_2])]) tuples """ - mgr = stevedore.named.NamedExtensionManager('oslo.config.opts', - names=namespaces, - invoke_on_load=True) + mgr = stevedore.named.NamedExtensionManager( + 'oslo.config.opts', + names=namespaces, + on_load_failure_callback=on_load_failure_callback, + invoke_on_load=True) return [(ep.name, ep.obj) for ep in mgr] +def on_load_failure_callback(*args, **kwargs): + raise + + def generate(conf): """Generate a sample config file. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/tests/test_cfg.py new/oslo.config-1.9.3/oslo_config/tests/test_cfg.py --- old/oslo.config-1.6.0/oslo_config/tests/test_cfg.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/tests/test_cfg.py 2015-03-12 17:23:28.000000000 +0100 @@ -28,6 +28,7 @@ import testscenarios from oslo_config import cfg +from oslo_config import types load_tests = testscenarios.load_tests_apply_scenarios @@ -273,6 +274,10 @@ IPv4Opt = functools.partial(cfg.IPOpt, version=4) IPv6Opt = functools.partial(cfg.IPOpt, version=6) + multi_int = functools.partial(cfg.MultiOpt, item_type=types.Integer()) + multi_float = functools.partial(cfg.MultiOpt, item_type=types.Float()) + multi_string = functools.partial(cfg.MultiOpt, item_type=types.String()) + scenarios = [ ('str_default', dict(opt_class=cfg.StrOpt, default=None, cli_args=[], value=None, @@ -480,6 +485,18 @@ dict(opt_class=cfg.MultiStrOpt, default=None, cli_args=['--old-oof', 'blaa', '--old-oof', 'bar'], value=['blaa', 'bar'], deps=('oof', 'old'))), + ('multiopt_arg_int', + dict(opt_class=multi_int, default=None, + cli_args=['--foo', '1', '--foo', '2'], + value=[1, 2], deps=(None, None))), + ('multiopt_float_int', + dict(opt_class=multi_float, default=None, + cli_args=['--foo', '1.2', '--foo', '2.3'], + value=[1.2, 2.3], deps=(None, None))), + ('multiopt_string', + dict(opt_class=multi_string, default=None, + cli_args=['--foo', 'bar', '--foo', 'baz'], + value=["bar", "baz"], deps=(None, None))), ] def test_cli(self): @@ -3462,6 +3479,29 @@ self.assertTrue(hasattr(self.conf, 'foo')) self.assertEqual(self.conf.foo, 'bar1') + def test_conf_file_choice_empty_value(self): + self.conf.register_opt(cfg.StrOpt('foo', + choices=['', 'bar1', 'bar2'])) + + paths = self.create_tempfiles([('test', '[DEFAULT]\n''foo = \n')]) + + self.conf(['--config-file', paths[0]]) + + self.assertTrue(hasattr(self.conf, 'foo')) + self.assertEqual(self.conf.foo, '') + + def test_conf_file_choice_none_value(self): + self.conf.register_opt(cfg.StrOpt('foo', + default=None, + choices=[None, 'bar1', 'bar2'])) + + paths = self.create_tempfiles([('test', '[DEFAULT]\n''\n')]) + + self.conf(['--config-file', paths[0]]) + + self.assertTrue(hasattr(self.conf, 'foo')) + self.assertEqual(self.conf.foo, None) + def test_conf_file_bad_choice_value(self): self.conf.register_opt(cfg.StrOpt('foo', choices=['bar1', 'bar2'])) @@ -3533,3 +3573,154 @@ def test_illegal_name(self): self.assertRaises(ValueError, cfg.BoolOpt, '_foo') + + +class SectionsTestCase(base.BaseTestCase): + def test_list_all_sections(self): + paths = self.create_tempfiles([('test.ini', + '[DEFAULT]\n' + 'foo = bar\n' + '[BLAA]\n' + 'bar = foo\n')]) + config = cfg.ConfigOpts() + config(args=[], default_config_files=[paths[0]]) + sections = set(config.list_all_sections()) + self.assertEqual(sections, set(['DEFAULT', 'BLAA'])) + + +class DeprecationWarningTestBase(BaseTestCase): + def setUp(self): + super(DeprecationWarningTestBase, self).setUp() + self.log_fixture = self.useFixture(fixtures.FakeLogger()) + self._parser_class = cfg.MultiConfigParser + + +class DeprecationWarningTestScenarios(DeprecationWarningTestBase): + scenarios = [('default-deprecated', dict(deprecated=True, + group='DEFAULT')), + ('default-not-deprecated', dict(deprecated=False, + group='DEFAULT')), + ('other-deprecated', dict(deprecated=True, + group='other')), + ('other-not-deprecated', dict(deprecated=False, + group='other')), + ] + + def test_deprecated_logging(self): + self.conf.register_opt(cfg.StrOpt('foo', deprecated_name='bar')) + self.conf.register_group(cfg.OptGroup('other')) + self.conf.register_opt(cfg.StrOpt('foo', deprecated_name='bar'), + group='other') + if self.deprecated: + content = 'bar=baz' + else: + content = 'foo=baz' + paths = self.create_tempfiles([('test', + '[' + self.group + ']\n' + + content + '\n')]) + + self.conf(['--config-file', paths[0]]) + # Reference these twice to verify they only get logged once + if self.group == 'DEFAULT': + self.assertEqual('baz', self.conf.foo) + self.assertEqual('baz', self.conf.foo) + else: + self.assertEqual('baz', self.conf.other.foo) + self.assertEqual('baz', self.conf.other.foo) + if self.deprecated: + expected = (self._parser_class._deprecated_opt_message % + ('bar', self.group, 'foo', self.group) + '\n') + else: + expected = '' + self.assertEqual(expected, self.log_fixture.output) + + +class DeprecationWarningTests(DeprecationWarningTestBase): + def test_DeprecatedOpt(self): + default_deprecated = [cfg.DeprecatedOpt('bar')] + other_deprecated = [cfg.DeprecatedOpt('baz', group='other')] + self.conf.register_group(cfg.OptGroup('other')) + self.conf.register_opt(cfg.StrOpt('foo', + deprecated_opts=default_deprecated)) + self.conf.register_opt(cfg.StrOpt('foo', + deprecated_opts=other_deprecated), + group='other') + paths = self.create_tempfiles([('test', + '[DEFAULT]\n' + + 'bar=baz\n' + + '[other]\n' + + 'baz=baz\n')]) + self.conf(['--config-file', paths[0]]) + self.assertEqual('baz', self.conf.foo) + self.assertEqual('baz', self.conf.other.foo) + self.assertIn('Option "bar" from group "DEFAULT"', + self.log_fixture.output) + self.assertIn('Option "baz" from group "other"', + self.log_fixture.output) + + def test_check_deprecated_default_none(self): + parser = self._parser_class() + deprecated_list = [(None, 'bar')] + parser._check_deprecated(('DEFAULT', 'bar'), (None, 'foo'), + deprecated_list) + self.assert_message_logged('bar', 'DEFAULT', 'foo', 'DEFAULT') + # Make sure check_deprecated didn't modify the list passed in + self.assertEqual([(None, 'bar')], deprecated_list) + + def test_check_deprecated_none_default(self): + parser = self._parser_class() + deprecated_list = [('DEFAULT', 'bar')] + parser._check_deprecated((None, 'bar'), ('DEFAULT', 'foo'), + deprecated_list) + self.assert_message_logged('bar', 'DEFAULT', 'foo', 'DEFAULT') + # Make sure check_deprecated didn't modify the list passed in + self.assertEqual([('DEFAULT', 'bar')], deprecated_list) + + def assert_message_logged(self, deprecated_name, deprecated_group, + current_name, current_group): + expected = (self._parser_class._deprecated_opt_message % + (deprecated_name, deprecated_group, + current_name, current_group) + ) + self.assertEqual(expected + '\n', self.log_fixture.output) + + def test_deprecated_for_removal(self): + self.conf.register_opt(cfg.StrOpt('foo', + deprecated_for_removal=True)) + self.conf.register_opt(cfg.StrOpt('bar', + deprecated_for_removal=True)) + paths = self.create_tempfiles([('test', + '[DEFAULT]\n' + + 'foo=bar\n')]) + self.conf(['--config-file', paths[0]]) + # Multiple references should be logged only once. + self.assertEqual('bar', self.conf.foo) + self.assertEqual('bar', self.conf.foo) + # Options not set in the config should not be logged. + self.assertEqual(None, self.conf.bar) + expected = ('Option "foo" from group "DEFAULT" is deprecated for ' + 'removal. Its value may be silently ignored in the ' + 'future.\n') + self.assertEqual(expected, self.log_fixture.output) + + def test_deprecated_for_removal_with_group(self): + self.conf.register_group(cfg.OptGroup('other')) + self.conf.register_opt(cfg.StrOpt('foo', + deprecated_for_removal=True), + group='other') + self.conf.register_opt(cfg.StrOpt('bar', + deprecated_for_removal=True), + group='other') + paths = self.create_tempfiles([('test', + '[other]\n' + + 'foo=bar\n')]) + self.conf(['--config-file', paths[0]]) + # Multiple references should be logged only once. + self.assertEqual('bar', self.conf.other.foo) + self.assertEqual('bar', self.conf.other.foo) + # Options not set in the config should not be logged. + self.assertEqual(None, self.conf.other.bar) + expected = ('Option "foo" from group "other" is deprecated for ' + 'removal. Its value may be silently ignored in the ' + 'future.\n') + self.assertEqual(expected, self.log_fixture.output) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/tests/test_cfgfilter.py new/oslo.config-1.9.3/oslo_config/tests/test_cfgfilter.py --- old/oslo.config-1.6.0/oslo_config/tests/test_cfgfilter.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/tests/test_cfgfilter.py 2015-03-12 17:23:28.000000000 +0100 @@ -278,3 +278,53 @@ self.fconf.import_group('fbaar', 'tests.testmods.fbaar_baa_opt') self.assertTrue(hasattr(self.fconf, 'fbaar')) self.assertTrue(hasattr(self.fconf.fbaar, 'baa')) + + +class ExposeTestCase(BaseTestCase): + + def test_expose_opt(self): + self.assertFalse(hasattr(self.conf, 'foo')) + self.assertFalse(hasattr(self.fconf, 'foo')) + + self.conf.register_opt(cfg.StrOpt('foo')) + self.conf.set_override('foo', 'bar') + + self.assertTrue(hasattr(self.conf, 'foo')) + self.assertEqual(self.conf.foo, 'bar') + self.assertFalse(hasattr(self.fconf, 'foo')) + + self.fconf.expose_opt('foo') + self.assertTrue(hasattr(self.conf, 'foo')) + self.assertTrue(hasattr(self.fconf, 'foo')) + self.assertEqual(self.fconf.foo, 'bar') + + def test_expose_opt_with_group(self): + self.assertFalse(hasattr(self.conf, 'foo')) + self.assertFalse(hasattr(self.fconf, 'foo')) + + self.conf.register_opt(cfg.StrOpt('foo'), group='group') + self.conf.set_override('foo', 'bar', group='group') + + self.assertTrue(hasattr(self.conf.group, 'foo')) + self.assertEqual(self.conf.group.foo, 'bar') + self.assertFalse(hasattr(self.fconf, 'group')) + + self.fconf.expose_opt('foo', group='group') + self.assertTrue(hasattr(self.conf.group, 'foo')) + self.assertTrue(hasattr(self.fconf.group, 'foo')) + self.assertEqual(self.fconf.group.foo, 'bar') + + def test_expose_group(self): + self.conf.register_opts([cfg.StrOpt('foo'), + cfg.StrOpt('bar')], group='group') + self.conf.register_opts([cfg.StrOpt('foo'), + cfg.StrOpt('bar')], group='another') + self.conf.set_override('foo', 'a', group='group') + self.conf.set_override('bar', 'b', group='group') + + self.fconf.expose_group('group') + + self.assertEqual('a', self.fconf.group.foo) + self.assertEqual('b', self.fconf.group.bar) + self.assertFalse(hasattr(self.fconf, 'another')) + self.assertTrue(hasattr(self.conf, 'another')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/tests/test_generator.py new/oslo.config-1.9.3/oslo_config/tests/test_generator.py --- old/oslo.config-1.6.0/oslo_config/tests/test_generator.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/tests/test_generator.py 2015-03-12 17:23:28.000000000 +0100 @@ -48,6 +48,10 @@ 'cupidatat non proident, sunt in culpa ' 'qui officia deserunt mollit anim id est ' 'laborum.'), + 'choices_opt': cfg.StrOpt('choices_opt', + default='a', + choices=(None, '', 'a', 'b', 'c'), + help='a string with choices'), 'deprecated_opt': cfg.StrOpt('bar', deprecated_name='foobar', help='deprecated'), @@ -281,6 +285,18 @@ ''' #long_help = <None> ''')), + ('choices_opt', + dict(opts=[('test', [(None, [opts['choices_opt']])])], + expected='''[DEFAULT] + +# +# From test +# + +# a string with choices (string value) +# Allowed values: <None>, '', a, b, c +#choices_opt = a +''')), ('deprecated', dict(opts=[('test', [('foo', [opts['deprecated_opt']])])], expected='''[DEFAULT] @@ -525,9 +541,11 @@ content = open(output_file).read() self.assertEqual(self.expected, content) - named_mgr.assert_called_once_with('oslo.config.opts', - names=namespaces, - invoke_on_load=True) + named_mgr.assert_called_once_with( + 'oslo.config.opts', + names=namespaces, + on_load_failure_callback=generator.on_load_failure_callback, + invoke_on_load=True) log_warning = getattr(self, 'log_warning', None) if log_warning is not None: @@ -536,4 +554,30 @@ self.assertFalse(mock_log.warning.called) +class GeneratorRaiseErrorTestCase(base.BaseTestCase): + + def test_generator_raises_error(self): + """Verifies that errors from extension manager are not suppressed.""" + class FakeException(Exception): + pass + + class FakeEP(object): + + def __init__(self): + self.name = 'callback_is_expected' + self.require = self.resolve + self.load = self.resolve + + def resolve(self, *args, **kwargs): + raise FakeException() + + fake_ep = FakeEP() + self.conf = cfg.ConfigOpts() + self.conf.register_opts(generator._generator_opts) + self.conf.set_default('namespace', fake_ep.name) + fake_eps = mock.Mock(return_value=[fake_ep]) + with mock.patch('pkg_resources.iter_entry_points', fake_eps): + self.assertRaises(FakeException, generator.generate, self.conf) + + GeneratorTestCase.generate_scenarios() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/tests/test_types.py new/oslo.config-1.9.3/oslo_config/tests/test_types.py --- old/oslo.config-1.6.0/oslo_config/tests/test_types.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/tests/test_types.py 2015-03-12 17:23:28.000000000 +0100 @@ -208,6 +208,7 @@ t(123) t(300) t(456) + self.assertRaises(ValueError, t, 0) self.assertRaises(ValueError, t, 457) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/oslo_config/types.py new/oslo.config-1.9.3/oslo_config/types.py --- old/oslo.config-1.6.0/oslo_config/types.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/oslo_config/types.py 2015-03-12 17:23:28.000000000 +0100 @@ -15,7 +15,7 @@ """Type conversion and validation classes for configuration options. Use these classes as values for the `type` argument to -:class:`oslo.config.cfg.Opt` and its subclasses. +:class:`oslo_config.cfg.Opt` and its subclasses. """ import netaddr @@ -144,7 +144,7 @@ else: value = int(value) - if value: + if value is not None: self._check_range(value) return value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/requirements.txt new/oslo.config-1.9.3/requirements.txt --- old/oslo.config-1.6.0/requirements.txt 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/requirements.txt 2015-03-12 17:23:28.000000000 +0100 @@ -5,5 +5,5 @@ pbr>=0.6,!=0.7,<1.0 argparse netaddr>=0.7.12 -six>=1.7.0 +six>=1.9.0 stevedore>=1.1.0 # Apache-2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/setup.cfg new/oslo.config-1.9.3/setup.cfg --- old/oslo.config-1.6.0/setup.cfg 2015-01-05 19:32:55.000000000 +0100 +++ new/oslo.config-1.9.3/setup.cfg 2015-03-12 17:23:49.000000000 +0100 @@ -48,7 +48,7 @@ universal = 1 [egg_info] -tag_svn_revision = 0 tag_build = +tag_svn_revision = 0 tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/test-requirements.txt new/oslo.config-1.9.3/test-requirements.txt --- old/oslo.config-1.6.0/test-requirements.txt 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/test-requirements.txt 2015-03-12 17:23:28.000000000 +0100 @@ -21,5 +21,8 @@ sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 oslosphinx>=2.2.0 # Apache-2.0 +# Required only for tests +oslo.i18n>=1.3.0 # Apache-2.0 + # mocking framework mock>=1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/tests/test_cfg.py new/oslo.config-1.9.3/tests/test_cfg.py --- old/oslo.config-1.6.0/tests/test_cfg.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/tests/test_cfg.py 2015-03-12 17:23:28.000000000 +0100 @@ -28,6 +28,7 @@ import testscenarios from oslo.config import cfg +from oslo.config import types load_tests = testscenarios.load_tests_apply_scenarios @@ -273,6 +274,10 @@ IPv4Opt = functools.partial(cfg.IPOpt, version=4) IPv6Opt = functools.partial(cfg.IPOpt, version=6) + multi_int = functools.partial(cfg.MultiOpt, item_type=types.Integer()) + multi_float = functools.partial(cfg.MultiOpt, item_type=types.Float()) + multi_string = functools.partial(cfg.MultiOpt, item_type=types.String()) + scenarios = [ ('str_default', dict(opt_class=cfg.StrOpt, default=None, cli_args=[], value=None, @@ -480,6 +485,18 @@ dict(opt_class=cfg.MultiStrOpt, default=None, cli_args=['--old-oof', 'blaa', '--old-oof', 'bar'], value=['blaa', 'bar'], deps=('oof', 'old'))), + ('multiopt_arg_int', + dict(opt_class=multi_int, default=None, + cli_args=['--foo', '1', '--foo', '2'], + value=[1, 2], deps=(None, None))), + ('multiopt_float_int', + dict(opt_class=multi_float, default=None, + cli_args=['--foo', '1.2', '--foo', '2.3'], + value=[1.2, 2.3], deps=(None, None))), + ('multiopt_string', + dict(opt_class=multi_string, default=None, + cli_args=['--foo', 'bar', '--foo', 'baz'], + value=["bar", "baz"], deps=(None, None))), ] def test_cli(self): @@ -653,20 +670,37 @@ command = cfg.StrOpt('command', positional=True) arg1 = cfg.StrOpt('arg1', positional=True) arg2 = cfg.StrOpt('arg2', positional=True) + cfg.CONF.register_group(cfg.OptGroup('blaa')) self.conf.register_cli_opt(command) self.conf.register_cli_opt(arg1) - self.conf.register_cli_opt(arg2) + self.conf.register_cli_opt(arg2, group='blaa') - self.conf(['command', 'arg1', 'arg2']) + self.assertEqual(3, len(self.conf._cli_opts)) + self.assertEqual(1, len(self.conf._groups)) - self.assertEqual('command', self.conf.command) - self.assertEqual('arg1', self.conf.arg1) - self.assertEqual('arg2', self.conf.arg2) + self.assertEqual('command', self.conf._cli_opts[0]['opt'].dest) + self.assertEqual('arg1', self.conf._cli_opts[1]['opt'].dest) + self.assertEqual('arg2', self.conf._cli_opts[2]['opt'].dest) + self.assertEqual('blaa', self.conf._cli_opts[2]['group'].name) + + self.conf(['command', 'arg1', 'arg2']) self.conf.reset() - self.conf.unregister_opt(arg1) - self.conf.unregister_opt(arg2) + new_arg1 = cfg.StrOpt('arg1', positional=True) + new_arg2 = cfg.StrOpt('arg2', positional=True) + + self.conf.unregister_opt(new_arg1) + self.assertEqual(2, len(self.conf._cli_opts)) + + self.assertRaises(cfg.NoSuchGroupError, + self.conf.unregister_opt, + new_arg2, + group='foo') + self.conf.unregister_opt(new_arg2, group='blaa') + self.assertEqual(1, len(self.conf._cli_opts)) + self.assertEqual('command', + self.conf._cli_opts[0]['opt'].dest) arg0 = cfg.StrOpt('arg0', positional=True) self.conf.register_cli_opt(arg0) @@ -674,9 +708,11 @@ self.conf(['command', 'arg0', 'arg1']) - self.assertEqual('command', self.conf.command) - self.assertEqual('arg0', self.conf.arg0) - self.assertEqual('arg1', self.conf.arg1) + self.conf.reset() + + self.assertEqual('command', self.conf._cli_opts[0]['opt'].dest) + self.assertEqual('arg0', self.conf._cli_opts[1]['opt'].dest) + self.assertEqual('arg1', self.conf._cli_opts[2]['opt'].dest) class ConfigFileOptsTestCase(BaseTestCase): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/oslo.config-1.6.0/tests/test_generator.py new/oslo.config-1.9.3/tests/test_generator.py --- old/oslo.config-1.6.0/tests/test_generator.py 2015-01-05 19:32:34.000000000 +0100 +++ new/oslo.config-1.9.3/tests/test_generator.py 2015-03-12 17:23:28.000000000 +0100 @@ -23,6 +23,7 @@ from oslo.config import cfg from oslo.config import fixture as config_fixture from oslo.config import generator +from oslo.i18n import fixture as i18n_fixture load_tests = testscenarios.load_tests_apply_scenarios @@ -31,6 +32,9 @@ opts = { 'foo': cfg.StrOpt('foo', help='foo option'), + 'foo_i18n_help': cfg.StrOpt('foo_i18n_help', + help=i18n_fixture.Translation().lazy( + 'this is a lazy message')), 'bar': cfg.StrOpt('bar', help='bar option'), 'foo-bar': cfg.StrOpt('foo-bar', help='foobar'), 'no_help': cfg.StrOpt('no_help'), @@ -48,6 +52,10 @@ 'cupidatat non proident, sunt in culpa ' 'qui officia deserunt mollit anim id est ' 'laborum.'), + 'choices_opt': cfg.StrOpt('choices_opt', + default='a', + choices=(None, '', 'a', 'b', 'c'), + help='a string with choices'), 'deprecated_opt': cfg.StrOpt('bar', deprecated_name='foobar', help='deprecated'), @@ -207,6 +215,17 @@ # foobar (string value) #foo_bar = <None> ''')), + ('i18n_help', + dict(opts=[('test', [(None, [opts['foo_i18n_help']])])], + expected='''[DEFAULT] + +# +# From test +# + +# this is a lazy message (string value) +#foo_i18n_help = <None> +''')), ('no_help', dict(opts=[('test', [(None, [opts['no_help']])])], log_warning=('"%s" is missing a help string', 'no_help'), @@ -281,6 +300,18 @@ ''' #long_help = <None> ''')), + ('choices_opt', + dict(opts=[('test', [(None, [opts['choices_opt']])])], + expected='''[DEFAULT] + +# +# From test +# + +# a string with choices (string value) +# Allowed values: <None>, '', a, b, c +#choices_opt = a +''')), ('deprecated', dict(opts=[('test', [('foo', [opts['deprecated_opt']])])], expected='''[DEFAULT] @@ -525,9 +556,11 @@ content = open(output_file).read() self.assertEqual(self.expected, content) - named_mgr.assert_called_once_with('oslo.config.opts', - names=namespaces, - invoke_on_load=True) + named_mgr.assert_called_once_with( + 'oslo.config.opts', + names=namespaces, + on_load_failure_callback=generator.on_load_failure_callback, + invoke_on_load=True) log_warning = getattr(self, 'log_warning', None) if log_warning is not None: