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