Add KeyValueAppendAction to osc-lib

This is required to support things like the '--hint' option for
'openstack server create', which allows you to specify arguments
multiple times.

Change-Id: If73cab759fa09bddf1ff519923c5972c3b2052b1
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2019-09-27 12:41:05 +01:00
parent a0d9746eb5
commit 1420035836
3 changed files with 82 additions and 1 deletions

View File

@ -23,7 +23,7 @@ from osc_lib.i18n import _
class KeyValueAction(argparse.Action):
"""A custom action to parse arguments as key=value pairs
Ensures that ``dest`` is a dict
Ensures that ``dest`` is a dict and values are strings.
"""
def __call__(self, parser, namespace, values, option_string=None):
@ -45,6 +45,35 @@ class KeyValueAction(argparse.Action):
raise argparse.ArgumentTypeError(msg % str(values))
class KeyValueAppendAction(argparse.Action):
"""A custom action to parse arguments as key=value pairs
Ensures that ``dest`` is a dict and values are lists of strings.
"""
def __call__(self, parser, namespace, values, option_string=None):
# Make sure we have an empty dict rather than None
if getattr(namespace, self.dest, None) is None:
setattr(namespace, self.dest, {})
# Add value if an assignment else remove it
if '=' in values:
key, value = values.split('=', 1)
# NOTE(qtang): Prevent null key setting in property
if '' == key:
msg = _("Property key must be specified: %s")
raise argparse.ArgumentTypeError(msg % str(values))
dest = getattr(namespace, self.dest)
if key in dest:
dest[key].append(value)
else:
dest[key] = [value]
else:
msg = _("Expected 'key=value' type, but got: %s")
raise argparse.ArgumentTypeError(msg % str(values))
class MultiKeyValueAction(argparse.Action):
"""A custom action to parse arguments as key1=value1,key2=value2 pairs

View File

@ -59,6 +59,53 @@ class TestKeyValueAction(utils.TestCase):
self.parser.parse_args, data)
class TestKeyValueAppendAction(utils.TestCase):
def setUp(self):
super(TestKeyValueAppendAction, self).setUp()
self.parser = argparse.ArgumentParser()
# Set up our typical usage
self.parser.add_argument(
'--hint',
metavar='<key=value>',
action=parseractions.KeyValueAppendAction,
help='Arbitrary key/value pairs to be sent to the scheduler for '
'custom use',
)
def test_good_values(self):
print(self.parser._get_optional_actions())
results = self.parser.parse_args([
'--hint', 'same_host=a0cf03a5-d921-4877-bb5c-86d26cf818e1',
'--hint', 'same_host=8c19174f-4220-44f0-824a-cd1eeef10287',
'--hint', 'query=[>=,$free_ram_mb,1024]',
])
actual = getattr(results, 'hint', {})
expect = {
'same_host': [
'a0cf03a5-d921-4877-bb5c-86d26cf818e1',
'8c19174f-4220-44f0-824a-cd1eeef10287',
],
'query': [
'[>=,$free_ram_mb,1024]',
],
}
self.assertEqual(expect, actual)
def test_error_values(self):
data_list = [
['--hint', 'red', ],
['--hint', '=', ],
['--hint', '=red', ]
]
for data in data_list:
self.assertRaises(argparse.ArgumentTypeError,
self.parser.parse_args, data)
class TestMultiKeyValueAction(utils.TestCase):
def setUp(self):

View File

@ -0,0 +1,5 @@
---
features:
- |
Add ``KeyValueAppendAction`` that allows key-value arguments to be specified
multiple times. For example: ``--property key1=value1 --property key1=value2``.