Merge pull request #43 from salt-formulas/pr/38
Pr/38 - rebased
diff --git a/reclass/datatypes/parameters.py b/reclass/datatypes/parameters.py
index cbee11f..6ad0d27 100644
--- a/reclass/datatypes/parameters.py
+++ b/reclass/datatypes/parameters.py
@@ -44,7 +44,7 @@
functionality and does not try to be a really mapping object.
'''
- def __init__(self, mapping, settings, uri, merge_initialise = True):
+ def __init__(self, mapping, settings, uri, parse_strings=True):
self._settings = settings
self._base = {}
self._uri = uri
@@ -54,14 +54,12 @@
self._resolve_errors = ResolveErrorList()
self._needs_all_envs = False
self._keep_overrides = False
+ self._parse_strings = parse_strings
if mapping is not None:
- if merge_initialise:
- # we initialise by merging
- self._keep_overrides = True
- self.merge(mapping)
- self._keep_overrides = False
- else:
- self._base = copy.deepcopy(mapping)
+ # we initialise by merging
+ self._keep_overrides = True
+ self.merge(mapping)
+ self._keep_overrides = False
#delimiter = property(lambda self: self._delimiter)
@@ -103,7 +101,7 @@
return value
else:
try:
- return Value(value, self._settings, self._uri)
+ return Value(value, self._settings, self._uri, parse_string=self._parse_strings)
except InterpolationError as e:
e.context = str(path)
raise
@@ -127,7 +125,7 @@
elif isinstance(new, ValueList):
values.extend(new)
else:
- values.append(Value(new, self._settings, self._uri))
+ values.append(Value(new, self._settings, self._uri, parse_string=self._parse_strings))
return values
@@ -154,7 +152,7 @@
for (key, newvalue) in iteritems(new):
if key.startswith(self._settings.dict_key_override_prefix) and not self._keep_overrides:
if not isinstance(newvalue, Value):
- newvalue = Value(newvalue, self._settings, self._uri)
+ newvalue = Value(newvalue, self._settings, self._uri, parse_string=self._parse_strings)
newvalue.overwrite = True
ret[key.lstrip(self._settings.dict_key_override_prefix)] = newvalue
else:
@@ -187,7 +185,7 @@
else:
return self._update_value(cur, new)
- def merge(self, other, wrap=True):
+ def merge(self, other):
"""Merge function (public edition).
Call _merge_recurse on self with either another Parameter object or a
@@ -203,15 +201,9 @@
self._unrendered = None
if isinstance(other, dict):
- if wrap:
- wrapped = self._wrap_dict(other, DictPath(self._settings.delimiter))
- else:
- wrapped = copy.deepcopy(other)
+ wrapped = self._wrap_dict(other, DictPath(self._settings.delimiter))
elif isinstance(other, self.__class__):
- if wrap:
- wrapped = self._wrap_dict(other._base, DictPath(self._settings.delimiter))
- else:
- wrapped = copy.deepcopy(other._base)
+ wrapped = self._wrap_dict(other._base, DictPath(self._settings.delimiter))
else:
raise TypeError('Cannot merge %s objects into %s' % (type(other),
self.__class__.__name__))
diff --git a/reclass/datatypes/tests/test_parameters.py b/reclass/datatypes/tests/test_parameters.py
index ecd112c..9b788dc 100644
--- a/reclass/datatypes/tests/test_parameters.py
+++ b/reclass/datatypes/tests/test_parameters.py
@@ -655,6 +655,26 @@
p1.interpolate()
self.assertEqual(p1.as_dict(), r)
+ def test_escaped_string_overwrites(self):
+ p1 = Parameters({ 'test': '\${not_a_ref}' }, SETTINGS, '')
+ p2 = Parameters({ 'test': '\${also_not_a_ref}' }, SETTINGS, '')
+ r = { 'test': '${also_not_a_ref}' }
+ p1.merge(p2)
+ p1.interpolate()
+ self.assertEqual(p1.as_dict(), r)
+
+ def test_escaped_string_in_ref_dict_overwrite(self):
+ p1 = Parameters({'a': { 'one': '\${not_a_ref}' }, 'b': { 'two': '\${also_not_a_ref}' }}, SETTINGS, '')
+ p2 = Parameters({'c': '${a}'}, SETTINGS, '')
+ p3 = Parameters({'c': '${b}'}, SETTINGS, '')
+ p4 = Parameters({'c': { 'one': '\${again_not_a_ref}' } }, SETTINGS, '')
+ r = {'a': {'one': '${not_a_ref}'}, 'b': {'two': '${also_not_a_ref}'}, 'c': {'one': '${again_not_a_ref}', 'two': '${also_not_a_ref}'}}
+ p1.merge(p2)
+ p1.merge(p3)
+ p1.merge(p4)
+ p1.interpolate()
+ self.assertEqual(p1.as_dict(), r)
+
if __name__ == '__main__':
unittest.main()
diff --git a/reclass/values/compitem.py b/reclass/values/compitem.py
index 765b323..c6e8863 100644
--- a/reclass/values/compitem.py
+++ b/reclass/values/compitem.py
@@ -39,6 +39,21 @@
def get_references(self):
return self._refs
+ def merge_over(self, item):
+ if item.type == Item.SCALAR or item.type == Item.COMPOSITE:
+ return self
+ elif item.type == Item.LIST:
+ if self._settings.allow_scalar_over_list or (self._settings.allow_none_override and self._value in [None, 'none', 'None']):
+ return self
+ else:
+ raise TypeError('allow scalar over list = False: cannot merge %s over %s' % (repr(self), repr(item)))
+ elif item.type == Item.DICTIONARY:
+ if self._settings.allow_scalar_over_dict or (self._settings.allow_none_override and self._value in [None, 'none', 'None']):
+ return self
+ else:
+ raise TypeError('allow scalar over dict = False: cannot merge %s over %s' % (repr(self), repr(item)))
+ raise TypeError('Cannot merge %s over %s' % (repr(self), repr(item)))
+
def render(self, context, inventory):
# Preserve type if only one item
if len(self._items) == 1:
diff --git a/reclass/values/scaitem.py b/reclass/values/scaitem.py
index 9de5681..f4265b5 100644
--- a/reclass/values/scaitem.py
+++ b/reclass/values/scaitem.py
@@ -18,7 +18,7 @@
return self._value
def merge_over(self, item):
- if item.type == Item.SCALAR:
+ if item.type == Item.SCALAR or item.type == Item.COMPOSITE:
return self
elif item.type == Item.LIST:
if self._settings.allow_scalar_over_list or (self._settings.allow_none_override and self._value is None):
diff --git a/reclass/values/value.py b/reclass/values/value.py
index 7a855ad..1a5b450 100644
--- a/reclass/values/value.py
+++ b/reclass/values/value.py
@@ -14,16 +14,19 @@
_parser = Parser()
- def __init__(self, value, settings, uri):
+ def __init__(self, value, settings, uri, parse_string=True):
self._settings = settings
self._uri = uri
self._overwrite = False
if isinstance(value, str):
- try:
- self._item = self._parser.parse(value, self._settings)
- except InterpolationError as e:
- e.uri = self._uri
- raise
+ if parse_string:
+ try:
+ self._item = self._parser.parse(value, self._settings)
+ except InterpolationError as e:
+ e.uri = self._uri
+ raise
+ else:
+ self._item = ScaItem(value, self._settings)
elif isinstance(value, list):
self._item = ListItem(value, self._settings)
elif isinstance(value, dict):
diff --git a/reclass/values/valuelist.py b/reclass/values/valuelist.py
index 460dff0..bdfa01a 100644
--- a/reclass/values/valuelist.py
+++ b/reclass/values/valuelist.py
@@ -109,9 +109,9 @@
deepCopied = False
else:
if isinstance(output, dict) and isinstance(new, dict):
- p1 = Parameters(output, self._settings, None, merge_initialise = False)
- p2 = Parameters(new, self._settings, None, merge_initialise = False)
- p1.merge(p2, wrap=False)
+ p1 = Parameters(output, self._settings, None, parse_strings=False)
+ p2 = Parameters(new, self._settings, None, parse_strings=False)
+ p1.merge(p2)
output = p1.as_dict()
continue
elif isinstance(output, list) and isinstance(new, list):