diff options
| author | Tang Chen <chen.tang@easystack.cn> | 2016-02-24 14:56:35 +0800 |
|---|---|---|
| committer | Tang Chen <chen.tang@easystack.cn> | 2016-02-27 03:53:32 +0800 |
| commit | ada06f4dc3df39db5e739ebd8d82ccd734a54a93 (patch) | |
| tree | 30ffc19ee5a6c7d99a2505599e234925a5e88691 /openstackclient/common | |
| parent | 2819450be5d4fa57c6efdb4cd225f59bab894fba (diff) | |
| download | python-openstackclient-ada06f4dc3df39db5e739ebd8d82ccd734a54a93.tar.gz | |
Add MultiKeyValueAction to custom parser action
Class MultiKeyValueAction will be used to parse arguments like this:
--route destination=xxx,gateway=xxx --route destination=yyy,gateway=yyy
The result is a list like this:
[{destination:xxx, gateway:xxx}, {destination:yyy, gateway:yyy}]
This action also contain validation of the parameters.
Change-Id: Ie3aa8635c6a13fc2e429fe6922acd681dc7244cf
Diffstat (limited to 'openstackclient/common')
| -rw-r--r-- | openstackclient/common/parseractions.py | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/openstackclient/common/parseractions.py b/openstackclient/common/parseractions.py index fd90369a..7d332a5f 100644 --- a/openstackclient/common/parseractions.py +++ b/openstackclient/common/parseractions.py @@ -17,6 +17,8 @@ import argparse +from openstackclient.i18n import _ + class KeyValueAction(argparse.Action): """A custom action to parse arguments as key=value pairs @@ -36,6 +38,85 @@ class KeyValueAction(argparse.Action): getattr(namespace, self.dest, {}).pop(values, None) +class MultiKeyValueAction(argparse.Action): + """A custom action to parse arguments as key1=value1,key2=value2 pairs + + Ensure that ``dest`` is a list. The list will finally contain multiple + dicts, with key=value pairs in them. + + NOTE: The arguments string should be a comma separated key-value pairs. + And comma(',') and equal('=') may not be used in the key or value. + """ + + def __init__(self, option_strings, dest, nargs=None, + required_keys=None, optional_keys=None, **kwargs): + """Initialize the action object, and parse customized options + + Required keys and optional keys can be specified when initializing + the action to enable the key validation. If none of them specified, + the key validation will be skipped. + + :param required_keys: a list of required keys + :param optional_keys: a list of optional keys + """ + if nargs: + raise ValueError("Parameter 'nargs' is not allowed, but got %s" + % nargs) + + super(MultiKeyValueAction, self).__init__(option_strings, + dest, **kwargs) + + # required_keys: A list of keys that is required. None by default. + if required_keys and not isinstance(required_keys, list): + raise TypeError("'required_keys' must be a list") + self.required_keys = set(required_keys or []) + + # optional_keys: A list of keys that is optional. None by default. + if optional_keys and not isinstance(optional_keys, list): + raise TypeError("'optional_keys' must be a list") + self.optional_keys = set(optional_keys or []) + + def __call__(self, parser, namespace, values, metavar=None): + # Make sure we have an empty list rather than None + if getattr(namespace, self.dest, None) is None: + setattr(namespace, self.dest, []) + + params = {} + for kv in values.split(','): + # Add value if an assignment else raise ArgumentTypeError + if '=' in kv: + params.update([kv.split('=', 1)]) + else: + msg = ("Expected key=value pairs separated by comma, " + "but got: %s" % (str(kv))) + raise argparse.ArgumentTypeError(self, msg) + + # Check key validation + valid_keys = self.required_keys | self.optional_keys + if valid_keys: + invalid_keys = [k for k in params if k not in valid_keys] + if invalid_keys: + msg = _("Invalid keys %(invalid_keys)s specified.\n" + "Valid keys are: %(valid_keys)s.") + raise argparse.ArgumentTypeError( + msg % {'invalid_keys': ', '.join(invalid_keys), + 'valid_keys': ', '.join(valid_keys)} + ) + + if self.required_keys: + missing_keys = [k for k in self.required_keys if k not in params] + if missing_keys: + msg = _("Missing required keys %(missing_keys)s.\n" + "Required keys are: %(required_keys)s.") + raise argparse.ArgumentTypeError( + msg % {'missing_keys': ', '.join(missing_keys), + 'required_keys': ', '.join(self.required_keys)} + ) + + # Update the dest dict + getattr(namespace, self.dest, []).append(params) + + class RangeAction(argparse.Action): """A custom action to parse a single value or a range of values |
