Fix indentical inventory queries with different flags returning incorrect data
With two indentical inventory queries, one with the AllEnvs flag and
one without both queries return the data from the query with the AllEnvs
flag set.
This fix adds a test to the invitem class when assembling the inventory
query result to check that the node environments match or that the
query has the AllEnvs flag set.
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):