Merge pull request #94 from salt-formulas/andrewp-fix-inv-query-overwriting
Fix identical inventory queries with different flags returning incorrect data
diff --git a/reclass/core.py b/reclass/core.py
index 1ce74ed..61443c2 100644
--- a/reclass/core.py
+++ b/reclass/core.py
@@ -25,6 +25,7 @@
from reclass.settings import Settings
from reclass.datatypes import Entity, Classes, Parameters, Exports
from reclass.errors import MappingFormatError, ClassNameResolveError, ClassNotFound, InvQueryClassNameResolveError, InvQueryClassNotFound, InvQueryError, InterpolationError, ResolveError
+from reclass.values import NodeInventory
from reclass.values.parser import Parser
@@ -172,6 +173,19 @@
return Parameters({}, self._settings, '')
def _get_inventory(self, all_envs, environment, queries):
+ '''
+ Returns a dictionary of NodeInventory objects, one per matching node. Exports
+ which are required for the given queries (or all exports if the queries is None)
+ are rendered, remaining exports are left unrendered.
+
+ Args:
+ all_envs - if True match export values from nodes in any environment
+ else if False match only for nodes in the same environment as the
+ environment parameter
+ environment - node environment to match against if all_envs is False
+ queries - list of inventory queries to determine required export values
+ or if None match all exports defined by a node
+ '''
inventory = {}
for nodename in self._storage.enumerate_nodes():
try:
@@ -191,6 +205,7 @@
except ClassNameResolveError as e:
raise InvQueryClassNameResolveError(e)
if queries is None:
+ # This only happens if reclass is called with the --inventory option
try:
node.interpolate_exports()
except InterpolationError as e:
@@ -203,7 +218,7 @@
except InterpolationError as e:
e.nodename = nodename
raise InvQueryError(q.contents, e, context=p, uri=q.uri)
- inventory[nodename] = node.exports.as_dict()
+ inventory[nodename] = NodeInventory(node.exports.as_dict(), node_base.environment == environment)
return inventory
def _node_entity(self, nodename):
diff --git a/reclass/datatypes/tests/test_entity.py b/reclass/datatypes/tests/test_entity.py
index f18f3fc..a2b71b5 100644
--- a/reclass/datatypes/tests/test_entity.py
+++ b/reclass/datatypes/tests/test_entity.py
@@ -11,9 +11,12 @@
from __future__ import print_function
from __future__ import unicode_literals
+from six import iteritems
+
from reclass.settings import Settings
from reclass.datatypes import Entity, Classes, Parameters, Applications, Exports
from reclass.errors import ResolveError
+from reclass.values import NodeInventory
import unittest
try:
@@ -167,6 +170,9 @@
class TestEntityNoMock(unittest.TestCase):
+ def _make_inventory(self, nodes):
+ return { name: NodeInventory(node, True) for name, node in iteritems(nodes) }
+
def test_interpolate_list_types(self):
node1_exports = Exports({'exps': [ '${one}' ] }, SETTINGS, 'first')
node1_parameters = Parameters({'alpha': [ '${two}', '${three}' ], 'one': 1, 'two': 2, 'three': 3 }, SETTINGS, 'first')
@@ -174,33 +180,37 @@
node2_exports = Exports({'exps': '${alpha}' }, SETTINGS, 'second')
node2_parameters = Parameters({}, SETTINGS, 'second')
node2_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node2_parameters, exports=node2_exports)
- r = {'exps': [ 1, 2, 3 ]}
+ result = {'exps': [ 1, 2, 3 ]}
node1_entity.merge(node2_entity)
node1_entity.interpolate(None)
self.assertIs(type(node1_entity.exports.as_dict()['exps']), list)
- self.assertDictEqual(node1_entity.exports.as_dict(), r)
+ self.assertDictEqual(node1_entity.exports.as_dict(), result)
def test_exports_with_refs(self):
- inventory = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
node3_exports = Exports({'a': '${a}', 'b': '${b}'}, SETTINGS, '')
node3_parameters = Parameters({'name': 'node3', 'a': '${c}', 'b': 5}, SETTINGS, '')
node3_parameters.merge({'c': 3})
node3_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node3_parameters, exports=node3_exports)
node3_entity.interpolate_exports()
- inventory['node3'] = node3_entity.exports.as_dict()
- r = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}, 'node3': {'a': 3, 'b': 5}}
- self.assertDictEqual(inventory, r)
+ inventory['node3'] = NodeInventory(node3_entity.exports.as_dict(), True)
+ result = { 'node1': NodeInventory({'a': 1, 'b': 2}, True),
+ 'node2': NodeInventory({'a': 3, 'b': 4}, True),
+ 'node3': NodeInventory({'a': 3, 'b': 5}, True) }
+ self.assertDictEqual(inventory, result)
def test_reference_to_an_export(self):
- inventory = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
node3_exports = Exports({'a': '${a}', 'b': '${b}'}, SETTINGS, '')
node3_parameters = Parameters({'name': 'node3', 'ref': '${exp}', 'a': '${c}', 'b': 5}, SETTINGS, '')
node3_parameters.merge({'c': 3, 'exp': '$[ exports:a ]'})
node3_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node3_parameters, exports=node3_exports)
node3_entity.interpolate_exports()
- inventory['node3'] = node3_entity.exports.as_dict()
+ inventory['node3'] = NodeInventory(node3_entity.exports.as_dict(), True)
node3_entity.interpolate(inventory)
- res_inv = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}, 'node3': {'a': 3, 'b': 5}}
+ res_inv = { 'node1': NodeInventory({'a': 1, 'b': 2}, True),
+ 'node2': NodeInventory({'a': 3, 'b': 4}, True),
+ 'node3': NodeInventory({'a': 3, 'b': 5}, True) }
res_params = {'a': 3, 'c': 3, 'b': 5, 'name': 'node3', 'exp': {'node1': 1, 'node3': 3, 'node2': 3}, 'ref': {'node1': 1, 'node3': 3, 'node2': 3}}
self.assertDictEqual(node3_parameters.as_dict(), res_params)
self.assertDictEqual(inventory, res_inv)
@@ -218,40 +228,61 @@
for p, q in queries:
node1_entity.interpolate_single_export(q)
node2_entity.interpolate_single_export(q)
- res_inv = {'node1': {'a': {'test': 1}}, 'node2': {'a': {'test': 2}}}
- res_params = {'a': {'test': 1}, 'b': 1, 'name': 'node1', 'exp': {'node1': {'test': 1}, 'node2': {'test': 2}}}
- inventory = {}
- inventory['node1'] = node1_entity.exports.as_dict()
- inventory['node2'] = node2_entity.exports.as_dict()
+ res_inv = { 'node1': NodeInventory({'a': {'test': 1}}, True),
+ 'node2': NodeInventory({'a': {'test': 2}}, True) }
+ res_params = { 'name': 'node1',
+ 'a': {'test': 1},
+ 'b': 1,
+ 'exp': {'node1': {'test': 1}, 'node2': {'test': 2}} }
+ inventory = self._make_inventory({'node1': node1_entity.exports.as_dict(), 'node2': node2_entity.exports.as_dict()})
node1_entity.interpolate(inventory)
self.assertDictEqual(node1_parameters.as_dict(), res_params)
self.assertDictEqual(inventory, res_inv)
def test_exports_with_ancestor_references(self):
- inventory = {'node1': {'alpha' : {'beta': {'a': 1, 'b': 2}}}, 'node2': {'alpha' : {'beta': {'a': 3, 'b': 4}}}}
+ inventory = self._make_inventory({'node1': {'alpha' : {'beta': {'a': 1, 'b': 2}}}, 'node2': {'alpha' : {'beta': {'a': 3, 'b': 4}}}})
node3_exports = Exports({'alpha': '${alpha}'}, SETTINGS, '')
node3_parameters = Parameters({'name': 'node3', 'alpha': {'beta' : {'a': 5, 'b': 6}}, 'exp': '$[ exports:alpha:beta ]'}, SETTINGS, '')
node3_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node3_parameters, exports=node3_exports)
- res_params = {'exp': {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}, 'node3': {'a': 5, 'b': 6}}, 'name': 'node3', 'alpha': {'beta': {'a': 5, 'b': 6}}}
- res_inv = {'node1': {'alpha' : {'beta': {'a': 1, 'b': 2}}}, 'node2': {'alpha' : {'beta': {'a': 3, 'b': 4}}}, 'node3': {'alpha' : {'beta': {'a': 5, 'b': 6}}}}
+ res_params = { 'name': 'node3',
+ 'exp': {'node1': {'a': 1, 'b': 2},
+ 'node2': {'a': 3, 'b': 4},
+ 'node3': {'a': 5, 'b': 6}},
+ 'alpha': {'beta': {'a': 5, 'b': 6}} }
+ res_inv = { 'node1': NodeInventory({'alpha' : {'beta': {'a': 1, 'b': 2}}}, True),
+ 'node2': NodeInventory({'alpha' : {'beta': {'a': 3, 'b': 4}}}, True),
+ 'node3': NodeInventory({'alpha' : {'beta': {'a': 5, 'b': 6}}}, True) }
node3_entity.initialise_interpolation()
queries = node3_entity.parameters.get_inv_queries()
for p, q in queries:
node3_entity.interpolate_single_export(q)
- inventory['node3'] = node3_entity.exports.as_dict()
+ inventory['node3'] = NodeInventory(node3_entity.exports.as_dict(), True)
node3_entity.interpolate(inventory)
self.assertDictEqual(node3_parameters.as_dict(), res_params)
self.assertDictEqual(inventory, res_inv)
def test_exports_with_nested_references(self):
- inventory = {'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}}
+ inventory = self._make_inventory({'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}})
node3_exports = Exports({'alpha': '${alpha}'}, SETTINGS, '')
- node3_parameters = Parameters({'name': 'node3', 'alpha': {'a': '${one}', 'b': '${two}'}, 'beta': '$[ exports:alpha ]', 'one': '111', 'two': '${three}', 'three': '123'}, SETTINGS, '')
+ node3_parameters = Parameters({ 'name': 'node3',
+ 'alpha': {'a': '${one}', 'b': '${two}'},
+ 'beta': '$[ exports:alpha ]',
+ 'one': '111',
+ 'two': '${three}',
+ 'three': '123'},
+ SETTINGS, '')
node3_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node3_parameters, exports=node3_exports)
- res_params = {'beta': {'node1': {'a': 1, 'b': 2}, 'node3': {'a': '111', 'b': '123'}, 'node2': {'a': 3, 'b': 4}}, 'name': 'node3', 'alpha': {'a': '111', 'b': '123'}, 'three': '123', 'two': '123', 'one': '111'}
- res_inv = {'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}, 'node3': {'alpha': {'a': '111', 'b': '123'}}}
+ res_params = { 'name': 'node3',
+ 'alpha': { 'a': '111', 'b': '123' },
+ 'beta': { 'node1': {'a': 1, 'b': 2 }, 'node2': { 'a': 3, 'b': 4}, 'node3': { 'a': '111', 'b': '123' } },
+ 'one': '111',
+ 'two': '123',
+ 'three': '123' }
+ res_inv = { 'node1': NodeInventory({'alpha': {'a': 1, 'b': 2}}, True),
+ 'node2': NodeInventory({'alpha': {'a': 3, 'b': 4}}, True),
+ 'node3': NodeInventory({'alpha': {'a': '111', 'b': '123'}}, True) }
node3_entity.interpolate_exports()
- inventory['node3'] = node3_entity.exports.as_dict()
+ inventory['node3'] = NodeInventory(node3_entity.exports.as_dict(), True)
node3_entity.interpolate(inventory)
self.assertDictEqual(node3_parameters.as_dict(), res_params)
self.assertDictEqual(inventory, res_inv)
@@ -285,11 +316,12 @@
for p, q in queries:
node1_entity.interpolate_single_export(q)
node2_entity.interpolate_single_export(q)
- res_inv = {'node1': {'a': 1}, 'node2': {}}
- res_params = { 'a': 1, 'name': 'node1', 'exp': {'node1': 1} }
- inventory = {}
- inventory['node1'] = node1_entity.exports.as_dict()
- inventory['node2'] = node2_entity.exports.as_dict()
+ res_inv = { 'node1': NodeInventory({'a': 1}, True),
+ 'node2': NodeInventory({}, True) }
+ res_params = { 'name': 'node1',
+ 'a': 1,
+ 'exp': {'node1': 1} }
+ inventory = self._make_inventory({'node1': node1_entity.exports.as_dict(), 'node2': node2_entity.exports.as_dict()})
node1_entity.interpolate(inventory)
self.assertDictEqual(node1_parameters.as_dict(), res_params)
self.assertDictEqual(inventory, res_inv)
diff --git a/reclass/datatypes/tests/test_exports.py b/reclass/datatypes/tests/test_exports.py
index 16a45cb..e0c5cc1 100644
--- a/reclass/datatypes/tests/test_exports.py
+++ b/reclass/datatypes/tests/test_exports.py
@@ -8,33 +8,39 @@
from __future__ import print_function
from __future__ import unicode_literals
+from six import iteritems
+
from reclass.utils.parameterdict import ParameterDict
from reclass.utils.parameterlist import ParameterList
from reclass.settings import Settings
from reclass.datatypes import Exports, Parameters
from reclass.errors import ParseError
+from reclass.values import NodeInventory
import unittest
SETTINGS = Settings()
class TestInvQuery(unittest.TestCase):
+ def _make_inventory(self, nodes):
+ return { name: NodeInventory(node, True) for name, node in iteritems(nodes) }
+
def test_overwrite_method(self):
- e = Exports({'alpha': { 'one': 1, 'two': 2}}, SETTINGS, '')
- d = {'alpha': { 'three': 3, 'four': 4}}
- e.overwrite(d)
- e.interpolate()
- self.assertEqual(e.as_dict(), d)
+ exports = Exports({'alpha': { 'one': 1, 'two': 2}}, SETTINGS, '')
+ data = {'alpha': { 'three': 3, 'four': 4}}
+ exports.overwrite(data)
+ exports.interpolate()
+ self.assertEqual(exports.as_dict(), data)
def test_interpolate_types(self):
- e = Exports({'alpha': { 'one': 1, 'two': 2}, 'beta': [ 1, 2 ]}, SETTINGS, '')
- r = {'alpha': { 'one': 1, 'two': 2}, 'beta': [ 1, 2 ]}
- self.assertIs(type(e.as_dict()['alpha']), ParameterDict)
- self.assertIs(type(e.as_dict()['beta']), ParameterList)
- e.interpolate()
- self.assertIs(type(e.as_dict()['alpha']), dict)
- self.assertIs(type(e.as_dict()['beta']), list)
- self.assertEqual(e.as_dict(), r)
+ exports = Exports({'alpha': { 'one': 1, 'two': 2}, 'beta': [ 1, 2 ]}, SETTINGS, '')
+ result = {'alpha': { 'one': 1, 'two': 2}, 'beta': [ 1, 2 ]}
+ self.assertIs(type(exports.as_dict()['alpha']), ParameterDict)
+ self.assertIs(type(exports.as_dict()['beta']), ParameterList)
+ exports.interpolate()
+ self.assertIs(type(exports.as_dict()['alpha']), dict)
+ self.assertIs(type(exports.as_dict()['beta']), list)
+ self.assertEqual(exports.as_dict(), result)
def test_malformed_invquery(self):
with self.assertRaises(ParseError):
@@ -51,83 +57,121 @@
p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value anddd exports:c == self:test_value2 ]'}, SETTINGS, '')
def test_value_expr_invquery(self):
- e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
- p = Parameters({'exp': '$[ exports:a ]'}, SETTINGS, '')
- r = {'exp': {'node1': 1, 'node2': 3}}
- p.interpolate(e)
- self.assertEqual(p.as_dict(), r)
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
+ parameters = Parameters({'exp': '$[ exports:a ]'}, SETTINGS, '')
+ result = {'exp': {'node1': 1, 'node2': 3}}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_if_expr_invquery(self):
- e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
- p = Parameters({'exp': '$[ exports:a if exports:b == 4 ]'}, SETTINGS, '')
- r = {'exp': {'node2': 3}}
- p.interpolate(e)
- self.assertEqual(p.as_dict(), r)
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
+ parameters = Parameters({'exp': '$[ exports:a if exports:b == 4 ]'}, SETTINGS, '')
+ result = {'exp': {'node2': 3}}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_if_expr_invquery_with_refs(self):
- e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
- p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value ]', 'test_value': 2}, SETTINGS, '')
- r = {'exp': {'node1': 1}, 'test_value': 2}
- p.interpolate(e)
- self.assertEqual(p.as_dict(), r)
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
+ parameters = Parameters({'exp': '$[ exports:a if exports:b == self:test_value ]', 'test_value': 2}, SETTINGS, '')
+ result = {'exp': {'node1': 1}, 'test_value': 2}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_list_if_expr_invquery(self):
- e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 2}}
- p = Parameters({'exp': '$[ if exports:b == 2 ]'}, SETTINGS, '')
- r1 = {'exp': ['node1', 'node3']}
- r2 = {'exp': ['node3', 'node1']}
- p.interpolate(e)
- self.assertIn(p.as_dict(), [ r1, r2 ])
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 2}})
+ parameters = Parameters({'exp': '$[ if exports:b == 2 ]'}, SETTINGS, '')
+ result = {'exp': ['node1', 'node3']}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_if_expr_invquery_wth_and(self):
- e = {'node1': {'a': 1, 'b': 4, 'c': False}, 'node2': {'a': 3, 'b': 4, 'c': True}}
- p = Parameters({'exp': '$[ exports:a if exports:b == 4 and exports:c == True ]'}, SETTINGS, '')
- r = {'exp': {'node2': 3}}
- p.interpolate(e)
- self.assertEqual(p.as_dict(), r)
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 4, 'c': False}, 'node2': {'a': 3, 'b': 4, 'c': True}})
+ parameters = Parameters({'exp': '$[ exports:a if exports:b == 4 and exports:c == True ]'}, SETTINGS, '')
+ result = {'exp': {'node2': 3}}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_if_expr_invquery_wth_or(self):
- e = {'node1': {'a': 1, 'b': 4}, 'node2': {'a': 3, 'b': 3}}
- p = Parameters({'exp': '$[ exports:a if exports:b == 4 or exports:b == 3 ]'}, SETTINGS, '')
- r = {'exp': {'node1': 1, 'node2': 3}}
- p.interpolate(e)
- self.assertEqual(p.as_dict(), r)
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 4}, 'node2': {'a': 3, 'b': 3}})
+ parameters = Parameters({'exp': '$[ exports:a if exports:b == 4 or exports:b == 3 ]'}, SETTINGS, '')
+ result = {'exp': {'node1': 1, 'node2': 3}}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_list_if_expr_invquery_with_and(self):
- e = {'node1': {'a': 1, 'b': 2, 'c': 'green'}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 2, 'c': 'red'}}
- p = Parameters({'exp': '$[ if exports:b == 2 and exports:c == green ]'}, SETTINGS, '')
- r = {'exp': ['node1']}
- p.interpolate(e)
- self.assertEqual(p.as_dict(), r)
+ inventory = self._make_inventory(
+ { 'node1': {'a': 1, 'b': 2, 'c': 'green'},
+ 'node2': {'a': 3, 'b': 3},
+ 'node3': {'a': 3, 'b': 2, 'c': 'red'} })
+ parameters = Parameters({'exp': '$[ if exports:b == 2 and exports:c == green ]'}, SETTINGS, '')
+ result = {'exp': ['node1']}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_list_if_expr_invquery_with_and_missing(self):
- inventory = {'node1': {'a': 1, 'b': 2, 'c': 'green'},
- 'node2': {'a': 3, 'b': 3},
- 'node3': {'a': 3, 'b': 2}}
+ inventory = self._make_inventory({'node1': {'a': 1, 'b': 2, 'c': 'green'},
+ 'node2': {'a': 3, 'b': 3},
+ 'node3': {'a': 3, 'b': 2}})
mapping = {'exp': '$[ if exports:b == 2 and exports:c == green ]'}
expected = {'exp': ['node1']}
+ parameterss = Parameters(mapping, SETTINGS, '')
+ parameterss.interpolate(inventory)
+ self.assertEqual(parameterss.as_dict(), expected)
- pars = Parameters(mapping, SETTINGS, '')
- pars.interpolate(inventory)
-
- self.assertEqual(pars.as_dict(), expected)
-
- def test_list_if_expr_invquery_with_and(self):
- e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 4}}
- p = Parameters({'exp': '$[ if exports:b == 2 or exports:b == 4 ]'}, SETTINGS, '')
- r1 = {'exp': ['node1', 'node3']}
- r2 = {'exp': ['node3', 'node1']}
- p.interpolate(e)
- self.assertIn(p.as_dict(), [ r1, r2 ])
+ def test_list_if_expr_invquery_with_or(self):
+ inventory = self._make_inventory(
+ { 'node1': {'a': 1, 'b': 2},
+ 'node2': {'a': 3, 'b': 3},
+ 'node3': {'a': 3, 'b': 4} })
+ parameters = Parameters({'exp': '$[ if exports:b == 2 or exports:b == 4 ]'}, SETTINGS, '')
+ result = {'exp': ['node1', 'node3']}
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
def test_merging_inv_queries(self):
- e = {'node1': {'a': 1}, 'node2': {'a': 1}, 'node3': {'a': 2}}
- p1 = Parameters({'exp': '$[ if exports:a == 1 ]'}, SETTINGS, '')
- p2 = Parameters({'exp': '$[ if exports:a == 2 ]'}, SETTINGS, '')
- r = { 'exp': [ 'node1', 'node2', 'node3' ] }
- p1.merge(p2)
- p1.interpolate(e)
- self.assertEqual(p1.as_dict(), r)
+ inventory = self._make_inventory({'node1': {'a': 1}, 'node2': {'a': 1}, 'node3': {'a': 2}})
+ pars1 = Parameters({'exp': '$[ if exports:a == 1 ]'}, SETTINGS, '')
+ pars2 = Parameters({'exp': '$[ if exports:a == 2 ]'}, SETTINGS, '')
+ result = { 'exp': [ 'node1', 'node2', 'node3' ] }
+ pars1.merge(pars2)
+ pars1.interpolate(inventory)
+ self.assertEqual(pars1.as_dict(), result)
+
+ def test_same_expr_invquery_different_flags(self):
+ inventory = { 'node1': NodeInventory({'a': 1}, True),
+ 'node2': NodeInventory({'a': 2}, True),
+ 'node3': NodeInventory({'a': 3}, False) }
+ parameters = Parameters({'alpha': '$[ exports:a ]', 'beta': '$[ +AllEnvs exports:a ]'}, SETTINGS, '')
+ result = { 'alpha': { 'node1': 1, 'node2': 2 },
+ 'beta': { 'node1': 1 , 'node2': 2, 'node3': 3 } }
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
+
+ def test_same_if_expr_invquery_different_flags(self):
+ inventory = { 'node1': NodeInventory({'a': 1, 'b': 1}, True),
+ 'node2': NodeInventory({'a': 2, 'b': 2}, True),
+ 'node3': NodeInventory({'a': 3, 'b': 2}, False) }
+ parameters = Parameters(
+ { 'alpha': '$[ exports:a if exports:b == 2 ]',
+ 'beta': '$[ +AllEnvs exports:a if exports:b == 2]' },
+ SETTINGS, '')
+ result = { 'alpha': { 'node2': 2 },
+ 'beta': { 'node2': 2, 'node3': 3 } }
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
+
+ def test_same_list_if_expr_invquery_different_flags(self):
+ inventory = { 'node1': NodeInventory({'a': 1}, True),
+ 'node2': NodeInventory({'a': 2}, True),
+ 'node3': NodeInventory({'a': 2}, False) }
+ parameters = Parameters(
+ { 'alpha': '$[ if exports:a == 2 ]',
+ 'beta': '$[ +AllEnvs if exports:a == 2]' },
+ SETTINGS, '')
+ result = { 'alpha': [ 'node2' ],
+ 'beta': [ 'node2', 'node3' ] }
+ parameters.interpolate(inventory)
+ self.assertEqual(parameters.as_dict(), result)
if __name__ == '__main__':
unittest.main()
diff --git a/reclass/values/__init__.py b/reclass/values/__init__.py
index ec0f882..0458d34 100644
--- a/reclass/values/__init__.py
+++ b/reclass/values/__init__.py
@@ -3,3 +3,7 @@
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
+
+import collections
+
+NodeInventory = collections.namedtuple('NodeInventory', ['items', 'env_matches'], rename=False)
diff --git a/reclass/values/invitem.py b/reclass/values/invitem.py
index adb1cb6..d8f3874 100644
--- a/reclass/values/invitem.py
+++ b/reclass/values/invitem.py
@@ -16,8 +16,7 @@
from six import iteritems
from six import string_types
-from reclass.values import item
-from reclass.values import parser_funcs
+from reclass.values import item, parser_funcs
from reclass.settings import Settings
from reclass.utils.dictpath import DictPath
from reclass.errors import ExpressionError, ParseError, ResolveError
@@ -200,10 +199,11 @@
def _value_expression(self, inventory):
results = {}
- for (node, items) in iteritems(inventory):
- if self._value_path.exists_in(items):
- results[node] = copy.deepcopy(self._resolve(self._value_path,
- items))
+ for name, node in iteritems(inventory):
+ if self.needs_all_envs or node.env_matches:
+ if self._value_path.exists_in(node.items):
+ answer = self._resolve(self._value_path, node.items)
+ results[name] = copy.deepcopy(answer)
return results
def _test_expression(self, context, inventory):
@@ -212,18 +212,21 @@
raise ExpressionError(msg % str(self), tbFlag=False)
results = {}
- for node, items in iteritems(inventory):
- if (self._question.value(context, items) and
- self._value_path.exists_in(items)):
- results[node] = copy.deepcopy(
- self._resolve(self._value_path, items))
+ for name, node in iteritems(inventory):
+ if self.needs_all_envs or node.env_matches:
+ if (self._question.value(context, node.items) and
+ self._value_path.exists_in(node.items)):
+ answer = self._resolve(self._value_path, node.items)
+ results[name] = copy.deepcopy(answer)
return results
def _list_test_expression(self, context, inventory):
results = []
- for (node, items) in iteritems(inventory):
- if self._question.value(context, items):
- results.append(node)
+ for name, node in iteritems(inventory):
+ if self.needs_all_envs or node.env_matches:
+ if self._question.value(context, node.items):
+ results.append(name)
+ results.sort()
return results
def render(self, context, inventory):