From 98faf03be4322a564b2012f07dcada7fb0552b5a Mon Sep 17 00:00:00 2001 From: Juan Antonio Osorio Robles Date: Thu, 20 Apr 2017 16:53:51 +0300 Subject: [PATCH] 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 --- doc/source/template_guide/hot_spec.rst | 26 +++++++++++ heat/engine/hot/functions.py | 44 +++++++++++++++++++ heat/engine/hot/template.py | 1 + heat/tests/test_hot.py | 20 +++++++++ ...list_concat-function-c28563ab8fb6362e.yaml | 4 ++ 5 files changed, 95 insertions(+) create mode 100644 releasenotes/notes/add-list_concat-function-c28563ab8fb6362e.yaml diff --git a/doc/source/template_guide/hot_spec.rst b/doc/source/template_guide/hot_spec.rst index cb3a5c80bc..87edffcf92 100644 --- a/doc/source/template_guide/hot_spec.rst +++ b/doc/source/template_guide/hot_spec.rst @@ -304,6 +304,7 @@ for the ``heat_template_version`` key: get_resource list_join make_url + list_concat map_merge map_replace repeat @@ -1893,3 +1894,28 @@ For example ``server_url`` will be evaluated to a URL in the form:: http://[]: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: + - + - + - ... + + +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. diff --git a/heat/engine/hot/functions.py b/heat/engine/hot/functions.py index b84dc0e53c..4c49ee45e4 100644 --- a/heat/engine/hot/functions.py +++ b/heat/engine/hot/functions.py @@ -1436,3 +1436,47 @@ class MakeURL(function.Function): return urlparse.urlunsplit((scheme, ''.join(netloc()), path, query, fragment)) + + +class ListConcat(function.Function): + """A function for extending lists. + + Takes the form:: + + list_concat: + - [, ] + - [, ] + + And resolves to:: + + [, , , ] + + """ + + def __init__(self, stack, fn_name, args): + super(ListConcat, self).__init__(stack, fn_name, args) + example = (_('"%s" : [ [ , ], ' + '[ , ] ]') + % 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 diff --git a/heat/engine/hot/template.py b/heat/engine/hot/template.py index ce9de81e18..44ca6cea81 100644 --- a/heat/engine/hot/template.py +++ b/heat/engine/hot/template.py @@ -590,6 +590,7 @@ class HOTemplate20170901(HOTemplate20170224): # functions added in 2017-09-01 'make_url': hot_funcs.MakeURL, + 'list_concat': hot_funcs.ListConcat, # functions removed from 2015-10-15 'Fn::Select': hot_funcs.Removed, diff --git a/heat/tests/test_hot.py b/heat/tests/test_hot.py index ec79974161..1f16894a04 100644 --- a/heat/tests/test_hot.py +++ b/heat/tests/test_hot.py @@ -2060,6 +2060,26 @@ conditions: stack.validate() 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): """Test stack function when stack was created from HOT template.""" diff --git a/releasenotes/notes/add-list_concat-function-c28563ab8fb6362e.yaml b/releasenotes/notes/add-list_concat-function-c28563ab8fb6362e.yaml new file mode 100644 index 0000000000..c498da36be --- /dev/null +++ b/releasenotes/notes/add-list_concat-function-c28563ab8fb6362e.yaml @@ -0,0 +1,4 @@ +--- +features: + - The list_concat function was added, which concats several lists using + python's extend function.