stop caching inventory and calculate inventory for nodes which have inventory queries
diff --git a/reclass/core.py b/reclass/core.py
index 14f56bd..e6962bc 100644
--- a/reclass/core.py
+++ b/reclass/core.py
@@ -120,7 +120,15 @@
else:
return Parameters()
- def _nodeinfo(self, nodename, exports):
+ def _get_inventory(self):
+ inventory = {}
+ for nodename in self._storage.enumerate_nodes():
+ node = self._node_entity(nodename)
+ node.interpolate_exports()
+ inventory[nodename] = node.exports.as_dict()
+ return inventory
+
+ def _node_entity(self, nodename):
node_entity = self._storage.get_node(nodename)
base_entity = Entity(name='base')
base_entity.merge(self._get_class_mappings_entity(node_entity.name))
@@ -129,9 +137,18 @@
seen = {}
merge_base = self._recurse_entity(base_entity, seen=seen,
nodename=base_entity.name)
- ret = self._recurse_entity(node_entity, merge_base, seen=seen,
+ return self._recurse_entity(node_entity, merge_base, seen=seen,
nodename=node_entity.name)
- ret.interpolate(nodename, exports)
+
+ def _nodeinfo(self, nodename, inventory):
+ ret = self._node_entity(nodename)
+ ret.initialise_interpolation()
+ if ret.parameters.has_inv_query():
+ if inventory is None:
+ inventory = self._get_inventory()
+ ret.interpolate(nodename, inventory)
+ else:
+ ret.interpolate(nodename, None)
return ret
def _nodeinfo_as_dict(self, nodename, entity):
@@ -144,40 +161,19 @@
ret.update(entity.as_dict())
return ret
- def _update_exports(self, old, new):
- if old != new:
- self._storage.put_exports(new)
- return True
- else:
- return False
-
def nodeinfo(self, nodename):
- original_exports = Exports(self._storage.get_exports())
- exports = copy.deepcopy(original_exports)
- original_exports.render_simple()
- ret = self._nodeinfo_as_dict(nodename, self._nodeinfo(nodename, exports))
- self._update_exports(original_exports, exports)
- return ret
+ return self._nodeinfo_as_dict(nodename, self._nodeinfo(nodename, None))
def inventory(self):
- original_exports = Exports(self._storage.get_exports())
- exports = copy.deepcopy(original_exports)
- original_exports.render_simple()
- nodes = { key for key in exports.as_dict()}
+ query_nodes = set()
entities = {}
+ inventory = self._get_inventory()
for n in self._storage.enumerate_nodes():
- entities[n] = self._nodeinfo(n, exports)
- nodes.discard(n)
- for n in nodes:
- exports.delete_key(n)
- changed = self._update_exports(original_exports, exports)
- if changed:
- # use brute force: if the exports have changed rerun
- # the inventory cacluation
- #exports = Parameters(exports.as_dict())
- entities = {}
- for n in self._storage.enumerate_nodes():
- entities[n] = self._nodeinfo(n, exports)
+ entities[n] = self._nodeinfo(n, inventory)
+ if entities[n].parameters.has_inv_query():
+ nodes.add(n)
+ for n in query_nodes:
+ entities[n] = self._nodeinfo(n, inventory)
nodes = {}
applications = {}
diff --git a/reclass/datatypes/entity.py b/reclass/datatypes/entity.py
index f73c137..706dd23 100644
--- a/reclass/datatypes/entity.py
+++ b/reclass/datatypes/entity.py
@@ -76,11 +76,17 @@
def merge_parameters(self, params):
self._parameters.merge(params)
- def interpolate(self, nodename, exports):
- exports.overwrite({ nodename: self._exports._base })
- self._parameters.interpolate(exports=exports._base)
+ def interpolate(self, nodename, inventory):
+ self._parameters.interpolate(inventory)
+ self.interpolate_exports()
+
+ def initialise_interpolation(self):
+ self._parameters.initialise_interpolation()
+ self._exports.initialise_interpolation()
+
+ def interpolate_exports(self):
+ self.initialise_interpolation()
self._exports.interpolate_from_external(self._parameters)
- exports.interpolate_from_external(self._parameters)
def __eq__(self, other):
return isinstance(other, type(self)) \
diff --git a/reclass/datatypes/parameters.py b/reclass/datatypes/parameters.py
index 1d4faf7..6fcdd6e 100644
--- a/reclass/datatypes/parameters.py
+++ b/reclass/datatypes/parameters.py
@@ -194,10 +194,6 @@
self.__class__.__name__))
self._base = self._merge_recurse(self._base, wrapped, DictPath(self._delimiter))
- def render_simple(self, options=None):
- self._unrendered = None
- self._initialise_interpolate(options)
-
def _render_simple_container(self, container, key, value, path):
if isinstance(value, ValueList):
if value.is_complex():
@@ -218,6 +214,8 @@
elif isinstance(value, Value):
if value.is_complex():
self._unrendered[path.new_subpath(key)] = True
+ if value.has_inv_query():
+ self._has_inv_query = True
else:
container[key] = value.render(None, None, self._options)
@@ -229,8 +227,8 @@
for n, value in enumerate(item_list):
self._render_simple_container(item_list, n, value, path)
- def interpolate(self, exports=None, options=None):
- self._initialise_interpolate(options)
+ def interpolate(self, exports=None):
+ self._initialise_interpolate(self._options)
while len(self._unrendered) > 0:
# we could use a view here, but this is simple enough:
# _interpolate_inner removes references from the refs hash after
@@ -238,6 +236,10 @@
path, v = self._unrendered.iteritems().next()
self._interpolate_inner(path, exports)
+ def initialise_interpolation(self, options=None):
+ self._unrendered = None
+ self._initialise_interpolate(options)
+
def _initialise_interpolate(self, options):
if options is None:
self._options = MergeOptions()
diff --git a/reclass/datatypes/tests/test_entity.py b/reclass/datatypes/tests/test_entity.py
index 76b90b9..8f693f1 100644
--- a/reclass/datatypes/tests/test_entity.py
+++ b/reclass/datatypes/tests/test_entity.py
@@ -158,38 +158,42 @@
class TestEntityNoMock(unittest.TestCase):
def test_exports_with_refs(self):
- exports = Exports({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
- exports_entity = Entity(None, None, None, exports)
+ inventory = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
node3_exports = Exports({'a': '${a}', 'b': '${b}'})
node3_parameters = Parameters({'name': 'node3', 'a': '${c}', 'b': 5})
node3_parameters.merge({'c': 3})
node3_entity = Entity(None, None, node3_parameters, 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}}
- node3_entity.interpolate('node3', exports)
- self.assertDictEqual(exports.as_dict(), r)
+ self.assertDictEqual(inventory, r)
def test_reference_to_an_export(self):
- exports = Exports({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
- exports_entity = Entity(None, None, None, exports)
+ inventory = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
node3_exports = Exports({'a': '${a}', 'b': '${b}'})
node3_parameters = Parameters({'name': 'node3', 'ref': '${exp}', 'a': '${c}', 'b': 5})
node3_parameters.merge({'c': 3, 'exp': '$[ exports:a ]'})
node3_entity = Entity(None, None, node3_parameters, node3_exports)
- r = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}, 'node3': {'a': 3, 'b': 5}}
- node3_entity.interpolate('node3', exports)
- self.assertDictEqual(exports.as_dict(), r)
+ node3_entity.interpolate_exports()
+ inventory['node3'] = node3_entity.exports.as_dict()
+ node3_entity.interpolate('node3', inventory)
+ res_inv = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}, 'node3': {'a': 3, 'b': 5}}
+ 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)
def test_exports_with_nested_references(self):
- exports = Exports({'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}})
- exports_entity = Entity(None, None, None, exports)
+ inventory = {'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}}
node3_exports = Exports({'alpha': '${alpha}'})
node3_parameters = Parameters({'name': 'node3', 'alpha': {'a': '${one}', 'b': '${two}'}, 'beta': '$[ exports:alpha ]', 'one': '111', 'two': '${three}', 'three': '123'})
node3_entity = Entity(None, None, node3_parameters, 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_exps = {'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}, 'node3': {'alpha': {'a': '111', 'b': '123'}}}
- node3_entity.interpolate('node3', exports)
+ res_inv = {'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}, 'node3': {'alpha': {'a': '111', 'b': '123'}}}
+ node3_entity.interpolate_exports()
+ inventory['node3'] = node3_entity.exports.as_dict()
+ node3_entity.interpolate('node3', inventory)
self.assertDictEqual(node3_parameters.as_dict(), res_params)
- self.assertDictEqual(exports.as_dict(), res_exps)
+ self.assertDictEqual(inventory, res_inv)
if __name__ == '__main__':
unittest.main()
diff --git a/reclass/datatypes/tests/test_exports.py b/reclass/datatypes/tests/test_exports.py
index f1b960b..1441117 100644
--- a/reclass/datatypes/tests/test_exports.py
+++ b/reclass/datatypes/tests/test_exports.py
@@ -17,7 +17,7 @@
e = Exports({'alpha': { 'one': 1, 'two': 2}})
d = {'alpha': { 'three': 3, 'four': 4}}
e.overwrite(d)
- e.render_simple()
+ e.initialise_interpolation()
self.assertEqual(e.as_dict(), d)
def test_value_expr_exports(self):
diff --git a/reclass/datatypes/tests/test_parameters.py b/reclass/datatypes/tests/test_parameters.py
index be54b19..0eb7815 100644
--- a/reclass/datatypes/tests/test_parameters.py
+++ b/reclass/datatypes/tests/test_parameters.py
@@ -145,7 +145,7 @@
p = Parameters(SIMPLE)
mergee = {'five':5,'four':4,'None':None,'tuple':(1,2,3)}
p.merge(mergee)
- p.render_simple()
+ p.initialise_interpolation()
goal = SIMPLE.copy()
goal.update(mergee)
self.assertDictEqual(p.as_dict(), goal)
@@ -154,7 +154,7 @@
p = Parameters(SIMPLE)
mergee = {'two':5,'four':4,'three':None,'one':(1,2,3)}
p.merge(mergee)
- p.render_simple()
+ p.initialise_interpolation()
goal = SIMPLE.copy()
goal.update(mergee)
self.assertDictEqual(p.as_dict(), goal)
@@ -165,7 +165,7 @@
p1 = Parameters(dict(list=l1[:]))
p2 = Parameters(dict(list=l2))
p1.merge(p2)
- p1.render_simple()
+ p1.initialise_interpolation()
self.assertListEqual(p1.as_dict()['list'], l1+l2)
def test_merge_list_into_scalar(self):
@@ -174,7 +174,7 @@
options.allow_list_over_scalar = True
p1 = Parameters(dict(key=l[0]))
p1.merge(Parameters(dict(key=l[1:])))
- p1.render_simple(options)
+ p1.initialise_interpolation(options)
self.assertListEqual(p1.as_dict()['key'], l)
def test_merge_scalar_over_list(self):
@@ -183,14 +183,14 @@
options.allow_scalar_over_list = True
p1 = Parameters(dict(key=l[:2]))
p1.merge(Parameters(dict(key=l[2])))
- p1.render_simple(options)
+ p1.initialise_interpolation(options)
self.assertEqual(p1.as_dict()['key'], l[2])
def test_merge_dicts(self):
mergee = {'five':5,'four':4,'None':None,'tuple':(1,2,3)}
p = Parameters(dict(dict=SIMPLE))
p.merge(Parameters(dict(dict=mergee)))
- p.render_simple()
+ p.initialise_interpolation()
goal = SIMPLE.copy()
goal.update(mergee)
self.assertDictEqual(p.as_dict(), dict(dict=goal))
@@ -199,7 +199,7 @@
mergee = {'two':5,'four':4,'three':None,'one':(1,2,3)}
p = Parameters(dict(dict=SIMPLE))
p.merge(Parameters(dict(dict=mergee)))
- p.render_simple()
+ p.initialise_interpolation()
goal = SIMPLE.copy()
goal.update(mergee)
self.assertDictEqual(p.as_dict(), dict(dict=goal))
@@ -214,7 +214,7 @@
'two': ['gamma']}
p = Parameters(dict(dict=base))
p.merge(Parameters(dict(dict=mergee)))
- p.render_simple()
+ p.initialise_interpolation()
self.assertDictEqual(p.as_dict(), dict(dict=goal))
def test_merge_dict_into_scalar(self):
@@ -229,7 +229,7 @@
options = MergeOptions()
options.allow_scalar_over_dict = True
p.merge(Parameters(mergee))
- p.render_simple(options)
+ p.initialise_interpolation(options)
self.assertDictEqual(p.as_dict(), mergee)
def test_interpolate_single(self):
@@ -359,7 +359,7 @@
d = {'foo': ESCAPE_CHARACTER + 'bar'.join(REFERENCE_SENTINELS),
'bar': 'unused'}
p = Parameters(d)
- p.render_simple()
+ p.initialise_interpolation()
self.assertEqual(p.as_dict()['foo'], v)
def test_interpolate_double_escaping(self):
@@ -385,7 +385,7 @@
])
d = {'foo': v}
p = Parameters(d)
- p.render_simple()
+ p.initialise_interpolation()
self.assertEqual(p.as_dict()['foo'], v)
def test_escape_close_in_ref(self):
diff --git a/reclass/values/valuelist.py b/reclass/values/valuelist.py
index 0071ffb..780eedd 100644
--- a/reclass/values/valuelist.py
+++ b/reclass/values/valuelist.py
@@ -12,20 +12,21 @@
self._refs = []
self._allRefs = True
self._values = [ value ]
- self.assembleRefs()
- self._has_env_query = False
- self._check_for_inv_query()
+ self._has_inv_query = False
+ self._update()
def append(self, value):
self._values.append(value)
- if value.has_references():
- self._refs.extend(value.get_references())
- if value.allRefs() is False:
- self._allRefs = False
+ self._update()
def extend(self, values):
self._values.extend(values._values)
+ self._update()
+
+ def _update(self):
+ self._has_inv_query = False
self.assembleRefs()
+ self._check_for_inv_query()
def has_references(self):
return len(self._refs) > 0