Hello community,

here is the log from the commit of package python-oslo.config for 
openSUSE:Factory checked in at 2018-01-17 21:56:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-oslo.config (Old)
 and      /work/SRC/openSUSE:Factory/.python-oslo.config.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-oslo.config"

Wed Jan 17 21:56:27 2018 rev:25 rq:565766 version:5.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-oslo.config/python-oslo.config.changes    
2018-01-10 23:35:59.205718376 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-oslo.config.new/python-oslo.config.changes   
    2018-01-17 21:56:32.396193449 +0100
@@ -1,0 +2,11 @@
+Mon Jan 15 11:50:59 UTC 2018 - cloud-de...@suse.de
+
+- update to version 5.2.0
+  - Clean up enforce_type related test method's name
+  - Remove -U from pip install
+  - Provide descriptions for choices
+  - Fix the invalid links for doc file in oslo.config
+  - Avoid tox_install.sh for constraints support
+  - sphinxext: Don't sometimes emit trailing newlines
+
+-------------------------------------------------------------------

Old:
----
  oslo.config-5.1.0.tar.gz

New:
----
  oslo.config-5.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-oslo.config.spec ++++++
--- /var/tmp/diff_new_pack.2rtRCf/_old  2018-01-17 21:56:33.064162204 +0100
+++ /var/tmp/diff_new_pack.2rtRCf/_new  2018-01-17 21:56:33.092160894 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-oslo.config
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,13 +17,13 @@
 
 
 Name:           python-oslo.config
-Version:        5.1.0
+Version:        5.2.0
 Release:        0
 Summary:        OpenStack common configuration library
 License:        Apache-2.0
 Group:          Development/Languages/Python
 Url:            https://launchpad.net/oslo.config
-Source0:        
https://files.pythonhosted.org/packages/source/o/oslo.config/oslo.config-5.1.0.tar.gz
+Source0:        
https://files.pythonhosted.org/packages/source/o/oslo.config/oslo.config-5.2.0.tar.gz
 BuildRequires:  openstack-macros
 BuildRequires:  python-devel
 BuildRequires:  python2-PyYAML >= 3.10
@@ -94,7 +94,7 @@
 Documentation for the oslo-config library.
 
 %prep
-%autosetup -p1 -n oslo.config-5.1.0
+%autosetup -p1 -n oslo.config-5.2.0
 %py_req_cleanup
 sed -i 's/^warning-is-error.*/warning-is-error = 0/g' setup.cfg
 

++++++ oslo.config-5.1.0.tar.gz -> oslo.config-5.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/AUTHORS 
new/oslo.config-5.2.0/AUTHORS
--- old/oslo.config-5.1.0/AUTHORS       2017-11-20 17:28:15.000000000 +0100
+++ new/oslo.config-5.2.0/AUTHORS       2018-01-08 15:15:24.000000000 +0100
@@ -164,6 +164,7 @@
 lzyeval <lzye...@gmail.com>
 melissaml <ma....@99cloud.net>
 ricolin <rico....@easystack.cn>
+shangxiaobj <shangxia...@inspur.com>
 skudriashev <skudrias...@griddynamics.com>
 sonu.kumar <sonu.ku...@nectechnologies.in>
 ting.wang <ting.w...@easystack.cn>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/ChangeLog 
new/oslo.config-5.2.0/ChangeLog
--- old/oslo.config-5.1.0/ChangeLog     2017-11-20 17:28:15.000000000 +0100
+++ new/oslo.config-5.2.0/ChangeLog     2018-01-08 15:15:24.000000000 +0100
@@ -1,6 +1,16 @@
 CHANGES
 =======
 
+5.2.0
+-----
+
+* Fix the invalid links for doc file in oslo.config
+* sphinxext: Don't sometimes emit trailing newlines
+* Provide descriptions for choices
+* Remove -U from pip install
+* Avoid tox\_install.sh for constraints support
+* Clean up enforce\_type related test method's name
+
 5.1.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/PKG-INFO 
new/oslo.config-5.2.0/PKG-INFO
--- old/oslo.config-5.1.0/PKG-INFO      2017-11-20 17:28:16.000000000 +0100
+++ new/oslo.config-5.2.0/PKG-INFO      2018-01-08 15:15:24.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: oslo.config
-Version: 5.1.0
+Version: 5.2.0
 Summary: Oslo Configuration API
 Home-page: https://docs.openstack.org/oslo.config/latest/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.config-5.1.0/doc/source/reference/styleguide.rst 
new/oslo.config-5.2.0/doc/source/reference/styleguide.rst
--- old/oslo.config-5.1.0/doc/source/reference/styleguide.rst   2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/doc/source/reference/styleguide.rst   2018-01-08 
15:12:21.000000000 +0100
@@ -9,7 +9,7 @@
 configuration files, such as ``etc/cinder/cinder.conf`` in the
 cinder repository. They are also displayed in the `OpenStack
 Configuration Reference
-<http://docs.openstack.org/draft/config-reference/index.html>`_.
+<https://docs.openstack.org/oslo.config/latest/reference/index.html>`_.
 
 Examples::
 
@@ -29,7 +29,7 @@
 
 2. Only use single spaces, no double spaces.
 
-3. Properly capitalize words. If in doubt check the `OpenStack Glossary 
<http://docs.openstack.org/user-guide/common/glossary.html>`_.
+3. Properly capitalize words. If in doubt check the `OpenStack Glossary 
<https://docs.openstack.org/oslo.config/latest/reference/styleguide.html#style-guide>`_.
 
 4. End each segment with a period and write complete sentences if
    possible. Examples::
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo.config.egg-info/PKG-INFO 
new/oslo.config-5.2.0/oslo.config.egg-info/PKG-INFO
--- old/oslo.config-5.1.0/oslo.config.egg-info/PKG-INFO 2017-11-20 
17:28:15.000000000 +0100
+++ new/oslo.config-5.2.0/oslo.config.egg-info/PKG-INFO 2018-01-08 
15:15:24.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: oslo.config
-Version: 5.1.0
+Version: 5.2.0
 Summary: Oslo Configuration API
 Home-page: https://docs.openstack.org/oslo.config/latest/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo.config.egg-info/SOURCES.txt 
new/oslo.config-5.2.0/oslo.config.egg-info/SOURCES.txt
--- old/oslo.config-5.1.0/oslo.config.egg-info/SOURCES.txt      2017-11-20 
17:28:16.000000000 +0100
+++ new/oslo.config-5.2.0/oslo.config.egg-info/SOURCES.txt      2018-01-08 
15:15:24.000000000 +0100
@@ -82,6 +82,7 @@
 releasenotes/notes/add-reno-71dc832ce29b962f.yaml
 releasenotes/notes/machine-readable-sample-config-e8f8ba43ababcf99.yaml
 releasenotes/notes/show-deprecated-reason-361a8eb31e05c97e.yaml
+releasenotes/notes/support-choice-descriptions-8b2d0c14fbd16b2a.yaml
 releasenotes/source/conf.py
 releasenotes/source/index.rst
 releasenotes/source/liberty.rst
@@ -91,5 +92,4 @@
 releasenotes/source/pike.rst
 releasenotes/source/unreleased.rst
 releasenotes/source/_static/.placeholder
-releasenotes/source/_templates/.placeholder
-tools/tox_install.sh
\ No newline at end of file
+releasenotes/source/_templates/.placeholder
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo.config.egg-info/pbr.json 
new/oslo.config-5.2.0/oslo.config.egg-info/pbr.json
--- old/oslo.config-5.1.0/oslo.config.egg-info/pbr.json 2017-11-20 
17:28:15.000000000 +0100
+++ new/oslo.config-5.2.0/oslo.config.egg-info/pbr.json 2018-01-08 
15:15:24.000000000 +0100
@@ -1 +1 @@
-{"git_version": "eb6ff02", "is_release": true}
\ No newline at end of file
+{"git_version": "5578616", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo_config/cfg.py 
new/oslo.config-5.2.0/oslo_config/cfg.py
--- old/oslo.config-5.1.0/oslo_config/cfg.py    2017-11-20 17:25:42.000000000 
+0100
+++ new/oslo.config-5.2.0/oslo_config/cfg.py    2018-01-08 15:12:21.000000000 
+0100
@@ -1225,7 +1225,8 @@
     Option with ``type`` :class:`oslo_config.types.String`
 
     :param name: the option's name
-    :param choices: Optional sequence of valid values.
+    :param choices: Optional sequence of either valid values or tuples of valid
+        values with descriptions.
     :param quotes: If True and string is enclosed with single or double
                    quotes, will strip those quotes.
     :param regex: Optional regular expression (string or compiled
@@ -1248,6 +1249,10 @@
 
     .. versionchanged:: 2.7
        Added *max_length* parameter
+
+    .. versionchanged:: 5.2
+       The *choices* parameter will now accept a sequence of tuples, where each
+       tuple is of form (*choice*, *description*)
     """
 
     def __init__(self, name, choices=None, quotes=None,
@@ -1275,10 +1280,11 @@
         if getattr(self.type, 'choices', None):
             choices_text = ', '.join([self._get_choice_text(choice)
                                       for choice in self.type.choices])
-            if kwargs['help'] is not None:
-                kwargs['help'] += (' Allowed values: %s\n' % choices_text)
-            else:
-                kwargs['help'] = (' Allowed values: %s\n' % choices_text)
+            if kwargs['help'] is None:
+                kwargs['help'] = ''
+
+            kwargs['help'].rstrip('\n')
+            kwargs['help'] += '\n Allowed values: %s\n' % choices_text
 
         return kwargs
 
@@ -1448,7 +1454,8 @@
     :param name: the option's name
     :param min: minimum value the port can take
     :param max: maximum value the port can take
-    :param choices: Optional sequence of valid values.
+    :param choices: Optional sequence of either valid values or tuples of valid
+        values with descriptions.
     :param \*\*kwargs: arbitrary keyword arguments passed to :class:`Opt`
 
     .. versionadded:: 2.6
@@ -1458,6 +1465,9 @@
        Allow port number with 0.
     .. versionchanged:: 3.16
        Added *min* and *max* parameters.
+    .. versionchanged:: 5.2
+       The *choices* parameter will now accept a sequence of tuples, where each
+       tuple is of form (*choice*, *description*)
     """
 
     def __init__(self, name, min=None, max=None, choices=None, **kwargs):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo_config/generator.py 
new/oslo.config-5.2.0/oslo_config/generator.py
--- old/oslo.config-5.1.0/oslo_config/generator.py      2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/oslo_config/generator.py      2018-01-08 
15:12:21.000000000 +0100
@@ -66,14 +66,18 @@
         'longer help text for Sphinx documents.'),
     cfg.StrOpt(
         'format',
-        help='Desired format for the output. "ini" is the only one which can '
-             'be used directly with oslo.config. "json" and "yaml" are '
-             'intended for third-party tools that want to write config files '
-             'based on the sample config data. "rst" can be used to dump '
-             'the text given to sphinx when building documentation using '
-             'the sphinx extension, for debugging.',
+        help='Desired format for the output.',
         default='ini',
-        choices=['ini', 'json', 'yaml', 'rst'],
+        choices=[
+            ('ini', 'The only format that can be used directly with '
+             'oslo.config.'),
+            ('json', 'Intended for third-party tools that want to write '
+             'config files based on the sample config data.'),
+            ('yaml', 'Same as json'),
+            ('rst', 'Can be used to dump the text given to Sphinx when '
+             'building documentation using the Sphinx extension. '
+             'Useful for debugging,')
+        ],
         dest='format_'),
 ]
 
@@ -257,9 +261,12 @@
             lines.append('# Maximum value: %d\n' % opt.type.max)
 
         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)
+            lines.append('# Possible values:\n')
+            for choice in opt.type.choices:
+                help_text = '%s - %s' % (
+                    self._get_choice_text(choice),
+                    opt.type.choices[choice] or '<No description provided>')
+                lines.extend(self._format_help(help_text))
 
         try:
             if opt.mutable:
@@ -581,9 +588,14 @@
     entry = {key: value for key, value in opt.__dict__.items()
              if not key.startswith('_')}
     entry['namespace'] = namespace
-    # In some types, choices is explicitly set to None.  Force it to [] so it
-    # is always an iterable type.
-    entry['choices'] = getattr(entry['type'], 'choices', []) or []
+    # Where present, we store choices as an OrderedDict. The default repr for
+    # this is not very machine readable, thus, it is switched to a list of
+    # tuples here. In addition, in some types, choices is explicitly set to
+    # None. Force these cases to [] so it is always an iterable type.
+    if getattr(entry['type'], 'choices', None):
+        entry['choices'] = list(entry['type'].choices.items())
+    else:
+        entry['choices'] = []
     entry['min'] = getattr(entry['type'], 'min', None)
     entry['max'] = getattr(entry['type'], 'max', None)
     entry['type'] = _format_type_name(entry['type'])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo_config/sphinxext.py 
new/oslo.config-5.2.0/oslo_config/sphinxext.py
--- old/oslo.config-5.1.0/oslo_config/sphinxext.py      2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/oslo_config/sphinxext.py      2018-01-08 
15:12:21.000000000 +0100
@@ -49,7 +49,6 @@
         yield '   - * %s' % row[0]
         for r in row[1:]:
             yield '     * %s' % r
-    yield ''
 
 
 def _indent(text, n=2):
@@ -152,7 +151,6 @@
                 'by the majority of users, and might have a significant', 6)
             yield _indent(
                 'effect on stability and/or performance.', 6)
-        yield ''
 
         try:
             help_text = opt.help % {'default': 'the value above'}
@@ -162,10 +160,23 @@
             # invalid formatting characters
             help_text = opt.help
         if help_text:
+            yield ''
             yield _indent(help_text)
+
+        # We don't bother outputting this if not using new-style choices with
+        # inline descriptions
+        if getattr(opt.type, 'choices', None) and not all(
+                x is None for x in opt.type.choices.values()):
             yield ''
+            yield _indent('.. rubric:: Possible values')
+            for choice in opt.type.choices:
+                yield ''
+                yield _indent(_get_choice_text(choice))
+                yield _indent(_indent(
+                    opt.type.choices[choice] or '<No description provided>'))
 
         if opt.deprecated_opts:
+            yield ''
             for line in _list_table(
                     ['Group', 'Name'],
                     ((d.group or group_name,
@@ -173,7 +184,9 @@
                      for d in opt.deprecated_opts),
                     title='Deprecated Variations'):
                 yield _indent(line)
+
         if opt.deprecated_for_removal:
+            yield ''
             yield _indent('.. warning::')
             if opt.deprecated_since:
                 yield _indent('   This option is deprecated for removal '
@@ -182,10 +195,9 @@
                 yield _indent('   This option is deprecated for removal.')
             yield _indent('   Its value may be silently ignored ')
             yield _indent('   in the future.')
-            yield ''
             if opt.deprecated_reason:
+                yield ''
                 yield _indent('   :Reason: ' + opt.deprecated_reason)
-            yield ''
 
         yield ''
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo_config/tests/test_cfg.py 
new/oslo.config-5.2.0/oslo_config/tests/test_cfg.py
--- old/oslo.config-5.1.0/oslo_config/tests/test_cfg.py 2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/oslo_config/tests/test_cfg.py 2018-01-08 
15:11:54.000000000 +0100
@@ -3237,16 +3237,7 @@
         self.assertRaises(ValueError,
                           self.conf.set_default, 'oo', 'c', 'f')
 
-    def test_enforce_type_default_override(self):
-        self.conf.register_opt(cfg.StrOpt('foo', default='foo'))
-        self.conf([])
-        self.assertEqual('foo', self.conf.foo)
-        self.conf.set_default('foo', 'bar')
-        self.assertEqual('bar', self.conf.foo)
-        self.conf.clear_default('foo')
-        self.assertEqual('foo', self.conf.foo)
-
-    def test_enforce_type_wrong_type_default(self):
+    def test_wrong_type_default_override(self):
         self.conf.register_opt(cfg.IntOpt('foo', default=1))
         self.conf([])
         self.assertEqual(1, self.conf.foo)
@@ -3322,7 +3313,7 @@
         self.conf.clear_override('foo')
         self.assertIsNone(self.conf.foo)
 
-    def test_enforce_type_str_override(self):
+    def test__str_override(self):
         self.conf.register_opt(cfg.StrOpt('foo'))
         self.conf.set_override('foo', True)
         self.conf([])
@@ -3330,7 +3321,7 @@
         self.conf.clear_override('foo')
         self.assertIsNone(self.conf.foo)
 
-    def test_enforce_type_wrong_type_override(self):
+    def test__wrong_type_override(self):
         self.conf.register_opt(cfg.IntOpt('foo'))
         self.assertRaises(ValueError, self.conf.set_override,
                           'foo', "not_really_a_int")
@@ -3349,7 +3340,7 @@
         self.assertRaises(ValueError,
                           self.conf.set_override, 'oo', 'c', 'f')
 
-    def test_enforce_type_bool_override(self):
+    def test_bool_override(self):
         self.conf.register_opt(cfg.BoolOpt('foo'))
         self.conf.set_override('foo', 'True')
         self.conf([])
@@ -3357,7 +3348,7 @@
         self.conf.clear_override('foo')
         self.assertIsNone(self.conf.foo)
 
-    def test_enforce_type_int_override_with_None(self):
+    def test_int_override_with_None(self):
         self.conf.register_opt(cfg.IntOpt('foo'))
         self.conf.set_override('foo', None)
         self.conf([])
@@ -3365,7 +3356,7 @@
         self.conf.clear_override('foo')
         self.assertIsNone(self.conf.foo)
 
-    def test_enforce_type_str_override_with_None(self):
+    def test_str_override_with_None(self):
         self.conf.register_opt(cfg.StrOpt('foo'))
         self.conf.set_override('foo', None)
         self.conf([])
@@ -3373,7 +3364,7 @@
         self.conf.clear_override('foo')
         self.assertIsNone(self.conf.foo)
 
-    def test_enforce_type_List_override(self):
+    def test_List_override(self):
         self.conf.register_opt(cfg.ListOpt('foo'))
         self.conf.set_override('foo', ['aa', 'bb'])
         self.conf([])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo_config/tests/test_fixture.py 
new/oslo.config-5.2.0/oslo_config/tests/test_fixture.py
--- old/oslo.config-5.1.0/oslo_config/tests/test_fixture.py     2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/oslo_config/tests/test_fixture.py     2018-01-08 
15:11:54.000000000 +0100
@@ -42,7 +42,7 @@
         self.assertEqual('changed_value',
                          f.conf.get('testing_option'))
 
-    def test_overridden_value_with_enforce_type(self):
+    def test_overridden_value_with_wrong_type(self):
         f = self._make_fixture()
         self.assertEqual(5, f.conf.get('test2'))
         self.assertEqual('a', f.conf.get('test3'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.config-5.1.0/oslo_config/tests/test_generator.py 
new/oslo.config-5.2.0/oslo_config/tests/test_generator.py
--- old/oslo.config-5.1.0/oslo_config/tests/test_generator.py   2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/oslo_config/tests/test_generator.py   2018-01-08 
15:12:21.000000000 +0100
@@ -431,7 +431,12 @@
 #
 
 # a string with choices (string value)
-# Allowed values: <None>, '', a, b, c
+# Possible values:
+# <None> - <No description provided>
+# '' - <No description provided>
+# a - <No description provided>
+# b - <No description provided>
+# c - <No description provided>
 #choices_opt = a
 ''')),
         ('deprecated opt without deprecated group',
@@ -1219,7 +1224,13 @@
                                 'help': '',
                                 'standard_opts': ['choices_opt'],
                                 'opts': [{'advanced': False,
-                                          'choices': (None, '', 'a', 'b', 'c'),
+                                          'choices': [
+                                              (None, None),
+                                              ('', None),
+                                              ('a', None),
+                                              ('b', None),
+                                              ('c', None)
+                                          ],
                                           'default': 'a',
                                           'deprecated_for_removal': False,
                                           'deprecated_opts': [],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.config-5.1.0/oslo_config/tests/test_sphinxext.py 
new/oslo.config-5.2.0/oslo_config/tests/test_sphinxext.py
--- old/oslo.config-5.1.0/oslo_config/tests/test_sphinxext.py   2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/oslo_config/tests/test_sphinxext.py   2018-01-08 
15:12:21.000000000 +0100
@@ -42,7 +42,6 @@
           :Default: ``<None>``
 
           this appears in the default group
-
         ''').lstrip(), results)
 
     def test_with_default_value(self):
@@ -66,7 +65,6 @@
           :Default: ``this is the default``
 
           this appears in the default group
-
         ''').lstrip(), results)
 
     def test_with_min(self):
@@ -88,7 +86,6 @@
           :Type: integer
           :Default: ``<None>``
           :Minimum Value: 1
-
         ''').lstrip(), results)
 
     def test_with_min_0(self):
@@ -110,7 +107,6 @@
           :Type: integer
           :Default: ``<None>``
           :Minimum Value: 0
-
         ''').lstrip(), results)
 
     def test_with_max(self):
@@ -132,7 +128,6 @@
           :Type: integer
           :Default: ``<None>``
           :Maximum Value: 1
-
         ''').lstrip(), results)
 
     def test_with_max_0(self):
@@ -154,7 +149,6 @@
           :Type: integer
           :Default: ``<None>``
           :Maximum Value: 0
-
         ''').lstrip(), results)
 
     def test_with_choices(self):
@@ -176,7 +170,50 @@
           :Type: string
           :Default: ``<None>``
           :Valid Values: a, b, c, <None>, ''
+        ''').lstrip(), results)
 
+    def test_with_choices_with_descriptions(self):
+        results = '\n'.join(list(sphinxext._format_group(
+            app=mock.Mock(),
+            namespace=None,
+            group_name=None,
+            group_obj=None,
+            opt_list=[
+                cfg.StrOpt(
+                    'opt_name',
+                    choices=[
+                        ('a', 'a is the best'),
+                        ('b', 'Actually, may-b I am better'),
+                        ('c', 'c, I am clearly the greatest'),
+                        (None, 'I am having none of this'),
+                        ('', '')]),
+            ],
+        )))
+        self.assertEqual(textwrap.dedent('''
+        .. oslo.config:group:: DEFAULT
+
+        .. oslo.config:option:: opt_name
+
+          :Type: string
+          :Default: ``<None>``
+          :Valid Values: a, b, c, <None>, ''
+
+          .. rubric:: Possible values
+
+          a
+            a is the best
+
+          b
+            Actually, may-b I am better
+
+          c
+            c, I am clearly the greatest
+
+          <None>
+            I am having none of this
+
+          ''
+            <No description provided>
         ''').lstrip(), results)
 
     def test_group_obj_without_help(self):
@@ -195,7 +232,6 @@
 
           :Type: string
           :Default: ``<None>``
-
         ''').lstrip(), results)
 
     def test_group_obj_with_help(self):
@@ -216,7 +252,6 @@
 
           :Type: string
           :Default: ``<None>``
-
         ''').lstrip(), results)
 
     def test_deprecated_opts_without_deprecated_group(self):
@@ -246,7 +281,6 @@
                * Name
              - * DEFAULT
                * deprecated_name
-
         ''').lstrip(), results)
 
     def test_deprecated_opts_with_deprecated_group(self):
@@ -277,7 +311,6 @@
                * Name
              - * deprecated_group
                * deprecated_name
-
         ''').lstrip(), results)
 
     def test_deprecated_for_removal(self):
@@ -317,7 +350,6 @@
           :Type: integer
           :Default: ``<None>``
           :Mutable: This option can be changed without restarting.
-
         ''').lstrip(), results)
 
     def test_not_mutable(self):
@@ -338,7 +370,6 @@
 
           :Type: integer
           :Default: ``<None>``
-
         ''').lstrip(), results)
 
     def test_advanced(self):
@@ -362,7 +393,6 @@
           :Advanced Option: Intended for advanced users and not used
               by the majority of users, and might have a significant
               effect on stability and/or performance.
-
         ''').lstrip(), results)
 
     def test_not_advanced(self):
@@ -383,7 +413,6 @@
 
           :Type: string
           :Default: ``<None>``
-
         ''').lstrip(), results)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo_config/tests/test_types.py 
new/oslo.config-5.2.0/oslo_config/tests/test_types.py
--- old/oslo.config-5.1.0/oslo_config/tests/test_types.py       2017-11-20 
17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/oslo_config/tests/test_types.py       2018-01-08 
15:12:21.000000000 +0100
@@ -67,6 +67,11 @@
         self.type_instance = types.String(choices=('foo', 'bar'))
         self.assertConvertedValue('foo', 'foo')
 
+    def test_listed_value_dict(self):
+        self.type_instance = types.String(choices=[
+            ('foo', 'ab'), ('bar', 'xy')])
+        self.assertConvertedValue('foo', 'foo')
+
     def test_unlisted_value(self):
         self.type_instance = types.String(choices=['foo', 'bar'])
         self.assertInvalid('baz')
@@ -98,7 +103,11 @@
 
     def test_repr_with_choices_tuple(self):
         t = types.String(choices=('foo', 'bar'))
-        self.assertEqual('String(choices=(\'foo\', \'bar\'))', repr(t))
+        self.assertEqual('String(choices=[\'foo\', \'bar\'])', repr(t))
+
+    def test_repr_with_choices_dict(self):
+        t = types.String(choices=[('foo', 'ab'), ('bar', 'xy')])
+        self.assertEqual('String(choices=[\'foo\', \'bar\'])', repr(t))
 
     def test_equal(self):
         self.assertTrue(types.String() == types.String())
@@ -108,9 +117,8 @@
         t2 = types.String(choices=['foo', 'bar'])
         t3 = types.String(choices=('foo', 'bar'))
         t4 = types.String(choices=['bar', 'foo'])
-        self.assertTrue(t1 == t2)
-        self.assertTrue(t1 == t3)
-        self.assertTrue(t1 == t4)
+        t5 = types.String(choices=[('foo', 'ab'), ('bar', 'xy')])
+        self.assertTrue(t1 == t2 == t3 == t4 == t5)
 
     def test_not_equal_with_different_choices(self):
         t1 = types.String(choices=['foo', 'bar'])
@@ -282,7 +290,11 @@
 
     def test_repr_with_choices_tuple(self):
         t = types.Integer(choices=(80, 457))
-        self.assertEqual('Integer(choices=(80, 457))', repr(t))
+        self.assertEqual('Integer(choices=[80, 457])', repr(t))
+
+    def test_repr_with_choices_dict(self):
+        t = types.Integer(choices=[(80, 'ab'), (457, 'xy')])
+        self.assertEqual('Integer(choices=[80, 457])', repr(t))
 
     def test_equal(self):
         self.assertTrue(types.Integer() == types.Integer())
@@ -302,8 +314,8 @@
         t1 = types.Integer(choices=[80, 457])
         t2 = types.Integer(choices=[457, 80])
         t3 = types.Integer(choices=(457, 80))
-        self.assertTrue(t1 == t2)
-        self.assertTrue(t1 == t3)
+        t4 = types.Integer(choices=[(80, 'ab'), (457, 'xy')])
+        self.assertTrue(t1 == t2 == t3 == t4)
 
     def test_not_equal(self):
         self.assertFalse(types.Integer(min=123) == types.Integer(min=456))
@@ -369,21 +381,24 @@
         self.assertRaises(ValueError, t, 201)
         self.assertRaises(ValueError, t, -457)
 
-    def test_with_choices_list(self):
-        t = types.Integer(choices=[80, 457])
+    def _test_with_choices(self, t):
         self.assertRaises(ValueError, t, 1)
         self.assertRaises(ValueError, t, 200)
         self.assertRaises(ValueError, t, -457)
         t(80)
         t(457)
 
+    def test_with_choices_list(self):
+        t = types.Integer(choices=[80, 457])
+        self._test_with_choices(t)
+
     def test_with_choices_tuple(self):
         t = types.Integer(choices=(80, 457))
-        self.assertRaises(ValueError, t, 1)
-        self.assertRaises(ValueError, t, 200)
-        self.assertRaises(ValueError, t, -457)
-        t(80)
-        t(457)
+        self._test_with_choices(t)
+
+    def test_with_choices_dict(self):
+        t = types.Integer(choices=[(80, 'ab'), (457, 'xy')])
+        self._test_with_choices(t)
 
 
 class FloatTypeTests(TypeTestHelper, unittest.TestCase):
@@ -865,16 +880,29 @@
 
     def test_repr_with_choices_tuple(self):
         t = types.Port(choices=(80, 457))
-        self.assertEqual('Port(choices=(80, 457))', repr(t))
+        self.assertEqual('Port(choices=[80, 457])', repr(t))
 
-    def test_choices(self):
-        t = types.Port(choices=[80, 457])
+    def _test_with_choices(self, t):
         self.assertRaises(ValueError, t, 1)
         self.assertRaises(ValueError, t, 200)
+        self.assertRaises(ValueError, t, -457)
         t(80)
         t(457)
 
+    def test_with_choices_list(self):
+        t = types.Port(choices=[80, 457])
+        self._test_with_choices(t)
+
+    def test_with_choices_tuple(self):
+        t = types.Port(choices=(80, 457))
+        self._test_with_choices(t)
+
+    def test_with_choices_dict(self):
+        t = types.Port(choices=[(80, 'ab'), (457, 'xy')])
+        self._test_with_choices(t)
+
     def test_invalid_choices(self):
+        """Check for choices that are specifically invalid for ports."""
         self.assertRaises(ValueError, types.Port, choices=[-1, 457])
         self.assertRaises(ValueError, types.Port, choices=[1, 2, 3, 65536])
 
@@ -896,8 +924,8 @@
         t1 = types.Port(choices=[80, 457])
         t2 = types.Port(choices=[457, 80])
         t3 = types.Port(choices=(457, 80))
-        self.assertTrue(t1 == t2)
-        self.assertTrue(t1 == t3)
+        t4 = types.Port(choices=[(457, 'ab'), (80, 'xy')])
+        self.assertTrue(t1 == t2 == t3 == t4)
 
     def test_not_equal(self):
         self.assertFalse(types.Port(min=123) == types.Port(min=456))
@@ -973,19 +1001,3 @@
         t = types.Port(max=0)
         self.assertRaises(ValueError, t, 1)
         t(0)
-
-    def test_with_choices_list(self):
-        t = types.Port(choices=[80, 457])
-        self.assertRaises(ValueError, t, 1)
-        self.assertRaises(ValueError, t, 200)
-        self.assertRaises(ValueError, t, -457)
-        t(80)
-        t(457)
-
-    def test_with_choices_tuple(self):
-        t = types.Port(choices=(80, 457))
-        self.assertRaises(ValueError, t, 1)
-        self.assertRaises(ValueError, t, 200)
-        self.assertRaises(ValueError, t, -457)
-        t(80)
-        t(457)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/oslo_config/types.py 
new/oslo.config-5.2.0/oslo_config/types.py
--- old/oslo.config-5.1.0/oslo_config/types.py  2017-11-20 17:25:42.000000000 
+0100
+++ new/oslo.config-5.2.0/oslo_config/types.py  2018-01-08 15:12:21.000000000 
+0100
@@ -19,6 +19,7 @@
 
 .. versionadded:: 1.3
 """
+import collections
 import operator
 import re
 import warnings
@@ -68,8 +69,8 @@
 
     String values do not get transformed and are returned as str objects.
 
-    :param choices: Optional sequence of valid values. Mutually
-                    exclusive with 'regex'.
+    :param choices: Optional sequence of either valid values or tuples of valid
+        values with descriptions. Mutually exclusive with 'regex'.
     :param quotes: If True and string is enclosed with single or double
                    quotes, will strip those quotes. Will signal error if
                    string have quote at the beginning and no quote at
@@ -96,6 +97,10 @@
     .. versionchanged:: 2.7
        Added *max_length* parameter.
        Added *type_name* parameter.
+
+    .. versionchanged:: 5.2
+       The *choices* parameter will now accept a sequence of tuples, where each
+       tuple is of form (*choice*, *description*)
     """
 
     def __init__(self, choices=None, quotes=False, regex=None,
@@ -109,10 +114,17 @@
         self.quotes = quotes
         self.max_length = max_length or 0
 
-        self.choices = choices
+        if choices is not None:
+            if not all(isinstance(choice, tuple) for choice in choices):
+                choices = [(choice, None) for choice in choices]
+
+            self.choices = collections.OrderedDict(choices)
+        else:
+            self.choices = None
+
         self.lower_case_choices = None
         if self.choices is not None and self.ignore_case:
-            self.lower_case_choices = [c.lower() for c in choices]
+            self.lower_case_choices = [c.lower() for c in self.choices]
 
         self.regex = regex
         if self.regex is not None:
@@ -146,7 +158,7 @@
         # Check for case insensitive
         processed_value, choices = ((value.lower(), self.lower_case_choices)
                                     if self.ignore_case else
-                                    (value, self.choices))
+                                    (value, self.choices.keys()))
         if processed_value in choices:
             return value
 
@@ -158,7 +170,7 @@
     def __repr__(self):
         details = []
         if self.choices is not None:
-            details.append("choices={!r}".format(self.choices))
+            details.append("choices={!r}".format(list(self.choices.keys())))
         if self.regex:
             details.append("regex=%r" % self.regex.pattern)
         if details:
@@ -168,11 +180,12 @@
     def __eq__(self, other):
         return (
             (self.__class__ == other.__class__) and
-            (set(self.choices) == set(other.choices) if
-             self.choices and other.choices else
-             self.choices == other.choices) and
             (self.quotes == other.quotes) and
-            (self.regex == other.regex)
+            (self.regex == other.regex) and
+            (set([x for x in self.choices or []]) ==
+                set([x for x in other.choices or []]) if
+             self.choices and other.choices else
+             self.choices == other.choices)
         )
 
     def _formatter(self, value):
@@ -252,9 +265,14 @@
     :param type_name: Type name to be used in the sample config file.
     :param min: Optional check that value is greater than or equal to min.
     :param max: Optional check that value is less than or equal to max.
-    :param choices: Optional sequence of valid values.
+    :param choices: Optional sequence of either valid values or tuples of valid
+        values with descriptions.
 
     .. versionadded:: 3.14
+
+    .. versionchanged:: 5.2
+       The *choices* parameter will now accept a sequence of tuples, where each
+       tuple is of form (*choice*, *description*)
     """
 
     def __init__(self, num_type, type_name,
@@ -263,15 +281,24 @@
 
         if min is not None and max is not None and max < min:
             raise ValueError('Max value is less than min value')
-        invalid_choices = [c for c in choices or []
+
+        if choices is not None:
+            if not all(isinstance(choice, tuple) for choice in choices):
+                choices = [(choice, None) for choice in choices]
+
+            self.choices = collections.OrderedDict(choices)
+        else:
+            self.choices = None
+
+        invalid_choices = [c for c in self.choices or []
                            if (min is not None and min > c)
                            or (max is not None and max < c)]
         if invalid_choices:
             raise ValueError("Choices %s are out of bounds [%s..%s]"
                              % (invalid_choices, min, max))
+
         self.min = min
         self.max = max
-        self.choices = choices
         self.num_type = num_type
 
     def __call__(self, value):
@@ -297,7 +324,7 @@
     def __repr__(self):
         props = []
         if self.choices is not None:
-            props.append("choices={!r}".format(self.choices))
+            props.append("choices={!r}".format(list(self.choices.keys())))
         else:
             if self.min is not None:
                 props.append('min=%g' % self.min)
@@ -313,7 +340,8 @@
             (self.__class__ == other.__class__) and
             (self.min == other.min) and
             (self.max == other.max) and
-            (set(self.choices) == set(other.choices) if
+            (set([x for x in self.choices or []]) ==
+                set([x for x in other.choices or []]) if
              self.choices and other.choices else
              self.choices == other.choices)
         )
@@ -332,7 +360,8 @@
     :param min: Optional check that value is greater than or equal to min.
     :param max: Optional check that value is less than or equal to max.
     :param type_name: Type name to be used in the sample config file.
-    :param choices: Optional sequence of valid values.
+    :param choices: Optional sequence of either valid values or tuples of valid
+        values with descriptions.
 
     .. versionchanged:: 2.4
        The class now honors zero for *min* and *max* parameters.
@@ -346,6 +375,10 @@
     .. versionchanged:: 3.16
        *choices* is no longer mutually exclusive with *min*/*max*. If those are
        supplied, all choices are verified to be within the range.
+
+    .. versionchanged:: 5.2
+       The *choices* parameter will now accept a sequence of tuples, where each
+       tuple is of form (*choice*, *description*)
     """
 
     def __init__(self, min=None, max=None, type_name='integer value',
@@ -385,9 +418,14 @@
     :param min: Optional check that value is greater than or equal to min.
     :param max: Optional check that value is less than or equal to max.
     :param type_name: Type name to be used in the sample config file.
-    :param choices: Optional sequence of valid values.
+    :param choices: Optional sequence of either valid values or tuples of valid
+        values with descriptions.
 
     .. versionadded:: 3.16
+
+    .. versionchanged:: 5.2
+       The *choices* parameter will now accept a sequence of tuples, where each
+       tuple is of form (*choice*, *description*)
     """
 
     PORT_MIN = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.config-5.1.0/releasenotes/notes/support-choice-descriptions-8b2d0c14fbd16b2a.yaml
 
new/oslo.config-5.2.0/releasenotes/notes/support-choice-descriptions-8b2d0c14fbd16b2a.yaml
--- 
old/oslo.config-5.1.0/releasenotes/notes/support-choice-descriptions-8b2d0c14fbd16b2a.yaml
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/oslo.config-5.2.0/releasenotes/notes/support-choice-descriptions-8b2d0c14fbd16b2a.yaml
  2018-01-08 15:12:21.000000000 +0100
@@ -0,0 +1,14 @@
+---
+features:
+  - |
+    String, Number, Integer, Float and Port now support value-description
+    tuples in the interable provided for the *choice* parameter. Support for
+    value-only definitions is retained.
+  - |
+    StringOpt and PortOpt now support a value-description tuples in the
+    iterable provided for the *choice* parameter. Support for value-only
+    definitions is retained.
+  - |
+    *oslo-config-generator* and the Sphinx extension will now output
+    descriptions for option choices where provided. This will impact tooling
+    that relies on the *yaml* and *json* output of the former.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/tools/tox_install.sh 
new/oslo.config-5.2.0/tools/tox_install.sh
--- old/oslo.config-5.1.0/tools/tox_install.sh  2017-11-20 17:25:42.000000000 
+0100
+++ new/oslo.config-5.2.0/tools/tox_install.sh  1970-01-01 01:00:00.000000000 
+0100
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-
-# Client constraint file contains this client version pin that is in conflict
-# with installing the client from source. We should remove the version pin in
-# the constraints file before applying it for from-source installation.
-
-CONSTRAINTS_FILE="$1"
-shift 1
-
-set -e
-
-# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
-# published to logs.openstack.org for easy debugging.
-localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
-
-if [[ "$CONSTRAINTS_FILE" != http* ]]; then
-    CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
-fi
-# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
-curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
-
-pip install -c"$localfile" openstack-requirements
-
-# This is the main purpose of the script: Allow local installation of
-# the current repo. It is listed in constraints file and thus any
-# install will be constrained and we need to unconstrain it.
-edit-constraints "$localfile" -- "$CLIENT_NAME"
-
-pip install -c"$localfile" -U "$@"
-exit $?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.config-5.1.0/tox.ini 
new/oslo.config-5.2.0/tox.ini
--- old/oslo.config-5.1.0/tox.ini       2017-11-20 17:25:42.000000000 +0100
+++ new/oslo.config-5.2.0/tox.ini       2018-01-08 15:11:54.000000000 +0100
@@ -4,12 +4,11 @@
 envlist = py35,py27,pep8
 
 [testenv]
-setenv =
-    VIRTUAL_ENV={envdir}
-    BRANCH_NAME=master
-    CLIENT_NAME=oslo.config
-install_command = {toxinidir}/tools/tox_install.sh 
{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
 {opts} {packages}
-deps = -r{toxinidir}/test-requirements.txt
+install_command = pip install {opts} {packages}
+deps =
+  
-c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+  -r{toxinidir}/test-requirements.txt
+  -r{toxinidir}/requirements.txt
 commands =
   python setup.py test --coverage --coverage-package-name=oslo_config 
--slowest --testr-args='{posargs}'
   coverage report --show-missing
@@ -32,7 +31,6 @@
 commands = python setup.py build_sphinx
 
 [testenv:bandit]
-deps = -r{toxinidir}/test-requirements.txt
 commands = bandit -r oslo_config -x tests -n5
 
 [flake8]


Reply via email to