Merge "Implement Parameter Deprecation"

This commit is contained in:
Jenkins 2016-11-15 19:28:23 +00:00 committed by Gerrit Code Review
commit 91bac9bd79
2 changed files with 89 additions and 2 deletions

View File

@ -35,6 +35,12 @@ from six import moves
from magnumclient.i18n import _
def deprecation_message(preamble, new_name):
msg = ('%s This parameter is deprecated and will be removed in a future '
'release. Use --%s instead.' % (preamble, new_name))
return msg
class MissingArgs(Exception):
"""Supplied arguments are not sufficient for calling a function."""
def __init__(self, missing):
@ -77,14 +83,14 @@ def validate_args(fn, *args, **kwargs):
def deprecated(message):
'''Decorator for marking a call as deprecated by printing a given message.
"""Decorator for marking a call as deprecated by printing a given message.
Example:
>>> @deprecated("Bay functions are deprecated and should be replaced by "
... "calls to cluster")
... def bay_create(args):
... pass
'''
"""
@decorator.decorator
def wrapper(func, *args, **kwargs):
print(message)
@ -92,6 +98,57 @@ def deprecated(message):
return wrapper
def deprecation_map(dep_map):
"""Decorator for applying a map of deprecating arguments to a function.
The map connects deprecating arguments and their replacements. The
shell.py script uses this map to create mutually exclusive argument groups
in argparse and also prints a deprecation warning telling the user to
switch to the updated argument.
NOTE: This decorator MUST be the outermost in the chain of argument
decorators to work correctly.
Example usage:
>>> @deprecation_map({ "old-argument": "new-argument" })
... @args("old-argument", required=True)
... @args("new-argument", required=True)
... def do_command_line_stuff():
... pass
"""
def _decorator(func):
if not hasattr(func, 'arguments'):
return func
func.deprecated_groups = []
for old_param, new_param in dep_map.items():
old_info, new_info = None, None
required = False
for (args, kwargs) in func.arguments:
if old_param in args:
old_info = (args, kwargs)
# Old arguments shouldn't be required if they were not
# previously, so prioritize old requirement
if 'required' in kwargs:
required = kwargs['required']
# Set to false so argparse doesn't get angry
kwargs['required'] = False
elif new_param in args:
new_info = (args, kwargs)
kwargs['required'] = False
if old_info and new_info:
break
# Add a tuple of (old, new, required), which in turn is:
# ((old_args, old_kwargs), (new_args, new_kwargs), required)
func.deprecated_groups.append((old_info, new_info, required))
# Remove arguments that would be duplicated by the groups we made
func.arguments.remove(old_info)
func.arguments.remove(new_info)
return func
return _decorator
def arg(*args, **kwargs):
"""Decorator for CLI args.

View File

@ -459,6 +459,7 @@ class OpenStackMagnumShell(object):
desc = callback.__doc__ or ''
action_help = desc.strip()
arguments = getattr(callback, 'arguments', [])
group_args = getattr(callback, 'deprecated_groups', [])
subparser = (
subparsers.add_parser(command,
@ -471,6 +472,12 @@ class OpenStackMagnumShell(object):
action='help',
help=argparse.SUPPRESS,)
self.subcommands[command] = subparser
for (old_info, new_info, req) in group_args:
group = subparser.add_mutually_exclusive_group(required=req)
group.add_argument(*old_info[0], **old_info[1])
group.add_argument(*new_info[0], **new_info[1])
for (args, kwargs) in arguments:
subparser.add_argument(*args, **kwargs)
subparser.set_defaults(func=callback)
@ -630,8 +637,31 @@ class OpenStackMagnumShell(object):
api_version=args.magnum_api_version,
)
self._check_deprecation(args.func, argv)
args.func(self.cs, args)
def _check_deprecation(self, func, argv):
if not hasattr(func, 'deprecated_groups'):
return
for (old_info, new_info, required) in func.deprecated_groups:
old_param = old_info[0][0]
new_param = new_info[0][0]
old_value, new_value = None, None
for i in range(len(argv)):
cur_arg = argv[i]
if cur_arg == old_param:
old_value = argv[i + 1]
elif cur_arg == new_param[0]:
new_value = argv[i + 1]
if old_value and not new_value:
print(
'WARNING: The %s parameter is deprecated and will be '
'removed in a future release. Use the %s parameter to '
'avoid seeing this message.'
% (old_param, new_param))
def _dump_timings(self, timings):
class Tyme(object):
def __init__(self, url, seconds):