Implement list_concat function

This function uses python's extend function for lists in order to
concatenate lists. So, given the input: [['v1', 'v2'], ['v3', 'v4']]
the result would be ['v1', 'v2', 'v3', 'v4'].

This comes as an alternative to using yaql's concat.

Change-Id: I082833e73388540b29f71b78293fd36fe04b7b92
This commit is contained in:
Juan Antonio Osorio Robles 2017-04-20 16:53:51 +03:00
parent 7dacf57a9a
commit 98faf03be4
5 changed files with 95 additions and 0 deletions

View File

@ -304,6 +304,7 @@ for the ``heat_template_version`` key:
get_resource get_resource
list_join list_join
make_url make_url
list_concat
map_merge map_merge
map_replace map_replace
repeat repeat
@ -1893,3 +1894,28 @@ For example
``server_url`` will be evaluated to a URL in the form:: ``server_url`` will be evaluated to a URL in the form::
http://[<server IP>]:8080/hello?recipient=world#greeting http://[<server IP>]:8080/hello?recipient=world#greeting
list_concat
-----------
The ``list_concat`` function concatenates lists together.
The syntax of the ``list_concat`` function is
.. code-block:: yaml
list_concat:
- <list #1>
- <list #2>
- ...
For example
.. code-block:: yaml
list_concat: [['v1', 'v2'], ['v3', 'v4']]
Will resolve to the list ``['v1', 'v2', 'v3', 'v4']``.
Null values will be ignored.

View File

@ -1436,3 +1436,47 @@ class MakeURL(function.Function):
return urlparse.urlunsplit((scheme, ''.join(netloc()), return urlparse.urlunsplit((scheme, ''.join(netloc()),
path, query, fragment)) path, query, fragment))
class ListConcat(function.Function):
"""A function for extending lists.
Takes the form::
list_concat:
- [<value 1>, <value 2>]
- [<value 3>, <value 4>]
And resolves to::
[<value 1>, <value 2>, <value 3>, <value 4>]
"""
def __init__(self, stack, fn_name, args):
super(ListConcat, self).__init__(stack, fn_name, args)
example = (_('"%s" : [ [ <value 1>, <value 2> ], '
'[ <value 3>, <value 4> ] ]')
% fn_name)
self.fmt_data = {'fn_name': fn_name, 'example': example}
def result(self):
args = function.resolve(self.args)
if not isinstance(args, collections.Sequence):
raise TypeError(_('Incorrect arguments to "%(fn_name)s" '
'should be: %(example)s') % self.fmt_data)
def ensure_list(m):
if m is None:
return []
elif isinstance(m, collections.Sequence):
return m
else:
msg = _('Incorrect arguments: Items to concat must be lists.')
raise TypeError(msg)
ret_list = []
for m in args:
ret_list.extend(ensure_list(m))
return ret_list

View File

@ -590,6 +590,7 @@ class HOTemplate20170901(HOTemplate20170224):
# functions added in 2017-09-01 # functions added in 2017-09-01
'make_url': hot_funcs.MakeURL, 'make_url': hot_funcs.MakeURL,
'list_concat': hot_funcs.ListConcat,
# functions removed from 2015-10-15 # functions removed from 2015-10-15
'Fn::Select': hot_funcs.Removed, 'Fn::Select': hot_funcs.Removed,

View File

@ -2060,6 +2060,26 @@ conditions:
stack.validate() stack.validate()
self.assertEqual({'one', 'three'}, set(stack.resources)) self.assertEqual({'one', 'three'}, set(stack.resources))
def test_list_concat(self):
snippet = {'list_concat': [['v1', 'v2'], ['v3', 'v4']]}
snippet_resolved = ['v1', 'v2', 'v3', 'v4']
tmpl = template.Template(hot_pike_tpl_empty)
resolved = self.resolve(snippet, tmpl)
self.assertEqual(snippet_resolved, resolved)
def test_list_concat_none(self):
snippet = {'list_concat': [['v1', 'v2'], ['v3', 'v4'], None]}
snippet_resolved = ['v1', 'v2', 'v3', 'v4']
tmpl = template.Template(hot_pike_tpl_empty)
resolved = self.resolve(snippet, tmpl)
self.assertEqual(snippet_resolved, resolved)
def test_list_concat_invalid(self):
snippet = {'list_concat': [{'k1': 'v2'}, ['v3', 'v4']]}
tmpl = template.Template(hot_pike_tpl_empty)
exc = self.assertRaises(TypeError, self.resolve, snippet, tmpl)
self.assertIn('Incorrect arguments', six.text_type(exc))
class HotStackTest(common.HeatTestCase): class HotStackTest(common.HeatTestCase):
"""Test stack function when stack was created from HOT template.""" """Test stack function when stack was created from HOT template."""

View File

@ -0,0 +1,4 @@
---
features:
- The list_concat function was added, which concats several lists using
python's extend function.