Add support for a deprecated version

It is possible to deprecate an option, but there's no clear way to
state when this deprecation occured and when the option will actually
go away. This leaves the user with a decision to make. Nova, for
example, frequently includes the release that the option was removed in
as part of the help message like so:

    "memcached_servers" opt is deprecated in Mitaka. In Newton release
    oslo.cache config options should be used as this option will be
    removed.

This is a decision that the user shouldn't have to make. Add a
'deprecated_since' parameter to allow users to specify this information
in a uniform manner. The parameter allows for any string value.

A future work item would add a hacking or tox check to compare this
parameter against the expected deprecation version. For example, to
ensure all Nova parameters deprecated in '13.0' should be removed in
'14.0'. This will be done on a per-project basis.

Change-Id: Ic894358006606f123e31611f068d9b6192d42616
This commit is contained in:
Stephen Finucane 2016-04-19 10:15:53 +01:00
parent b5d65b025c
commit 1543359b2b
5 changed files with 27 additions and 3 deletions

View File

@ -662,6 +662,10 @@ class Opt(object):
:param deprecated_reason: indicates why this opt is planned for removal in
a future release. Silently ignored if
deprecated_for_removal is False
:param deprecated_since: indicates which release this opt was deprecated
in. Accepts any string, though valid version
strings are encouraged. Silently ignored if
deprecated_for_removal is False
:param mutable: True if this option may be reloaded
An Opt object has no public methods, but has a number of public properties:
@ -722,6 +726,9 @@ class Opt(object):
.. versionchanged:: 3.5
Added *mutable* parameter.
.. versionchanged:: 3.12
Added *deprecated_since* parameter.
"""
multi = False
@ -731,7 +738,7 @@ class Opt(object):
deprecated_name=None, deprecated_group=None,
deprecated_opts=None, sample_default=None,
deprecated_for_removal=False, deprecated_reason=None,
mutable=False):
deprecated_since=None, mutable=False):
if name.startswith('_'):
raise ValueError('illegal name %s with prefix _' % (name,))
self.name = name
@ -757,6 +764,7 @@ class Opt(object):
self.required = required
self.deprecated_for_removal = deprecated_for_removal
self.deprecated_reason = deprecated_reason
self.deprecated_since = deprecated_since
self._logged_deprecation = False
if deprecated_name is not None:
deprecated_name = deprecated_name.replace('-', '_')

View File

@ -227,8 +227,14 @@ class _OptFormatter(object):
(d.group or group_name, d.name or opt.dest))
if opt.deprecated_for_removal:
if opt.deprecated_since:
lines.append(
'# This option is deprecated for removal since %s.\n' % (
opt.deprecated_since))
else:
lines.append(
'# This option is deprecated for removal.\n')
lines.append(
'# This option is deprecated for removal.\n'
'# Its value may be silently ignored in the future.\n')
if opt.deprecated_reason:
lines.extend(

View File

@ -161,7 +161,11 @@ def _format_group(app, namespace, group_name, group_obj, opt_list):
yield _indent(line)
if opt.deprecated_for_removal:
yield _indent('.. warning::')
yield _indent(' This option is deprecated for removal.')
if opt.deprecated_since:
yield _indent(' This option is deprecated for removal '
'since %s.' % opt.deprecated_since)
else:
yield _indent(' This option is deprecated for removal.')
yield _indent(' Its value may be silently ignored ')
yield _indent(' in the future.')
yield ''

View File

@ -91,6 +91,10 @@ class GeneratorTestCase(base.BaseTestCase):
deprecated_reason='This was supposed to work but it really, '
'really did not. Always buy house insurance.',
help='DEPRECATED: Turn off stove'),
'deprecated_opt_with_deprecated_since': cfg.BoolOpt(
'tune_in',
deprecated_for_removal=True,
deprecated_since='13.0'),
'deprecated_opt_with_deprecated_group': cfg.StrOpt(
'bar', deprecated_name='foobar', deprecated_group='group1',
help='deprecated'),

View File

@ -290,11 +290,13 @@ class FormatGroupTest(base.BaseTestCase):
cfg.StrOpt('opt_name',
deprecated_for_removal=True,
deprecated_reason='because I said so',
deprecated_since='13.0',
)
],
)))
self.assertIn('.. warning::', results)
self.assertIn('because I said so', results)
self.assertIn('since 13.0', results)
def test_mutable(self):
results = '\n'.join(list(sphinxext._format_group(