[core] split uids computation + cache override in updateInternals

* add _computeUids internal method + store computed uids in a dedicated dict
* cache override:
  * add optional cacheDir parameter on updateInternal method to override graph cache directory
  * _buildCmdVars always update member variable '_cmdVars' 
  * CameraInit: ensure node does not belong to a graph and use updateInternals with temp cache directory
This commit is contained in:
Yann Lanthony 2018-07-15 12:35:33 +02:00
parent 727950afef
commit 67ac4bf2ca
2 changed files with 34 additions and 30 deletions

View file

@ -309,6 +309,7 @@ class Node(BaseObject):
self.graph = None # type: Graph self.graph = None # type: Graph
self.dirty = True # whether this node's outputs must be re-evaluated on next Graph update self.dirty = True # whether this node's outputs must be re-evaluated on next Graph update
self._chunks = ListModel(parent=self) self._chunks = ListModel(parent=self)
self._uids = dict()
self._cmdVars = {} self._cmdVars = {}
self._size = 0 self._size = 0
self._attributes = DictModel(keyAttrName='name', parent=self) self._attributes = DictModel(keyAttrName='name', parent=self)
@ -404,11 +405,18 @@ class Node(BaseObject):
'attributes': {k: v for k, v in attributes.items() if v is not None}, # filter empty values 'attributes': {k: v for k, v in attributes.items() if v is not None}, # filter empty values
} }
def _buildCmdVars(self, cmdVars): def _computeUids(self):
""" Compute node uids by combining associated attributes' uids. """
for uidIndex, associatedAttributes in self.attributesPerUid.items(): for uidIndex, associatedAttributes in self.attributesPerUid.items():
assAttr = [(a.getName(), a.uid(uidIndex)) for a in associatedAttributes] # uid is computed by hashing the sorted list of tuple (name, value) of all attributes impacting this uid
assAttr.sort() uidAttributes = [(a.getName(), a.uid(uidIndex)) for a in associatedAttributes]
cmdVars['uid{}'.format(uidIndex)] = hashValue(assAttr) uidAttributes.sort()
self._uids[uidIndex] = hashValue(uidAttributes)
def _buildCmdVars(self):
""" Generate command variables using input attributes and resolved output attributes names and values. """
for uidIndex, value in self._uids.items():
self._cmdVars['uid{}'.format(uidIndex)] = value
# Evaluate input params # Evaluate input params
for name, attr in self._attributes.objects.items(): for name, attr in self._attributes.objects.items():
@ -416,33 +424,31 @@ class Node(BaseObject):
continue # skip outputs continue # skip outputs
v = attr.getValueStr() v = attr.getValueStr()
cmdVars[name] = '--{name} {value}'.format(name=name, value=v) self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v)
cmdVars[name + 'Value'] = str(v) self._cmdVars[name + 'Value'] = str(v)
if v is not None and v is not '': if v is not None and v is not '':
cmdVars[attr.attributeDesc.group] = cmdVars.get(attr.attributeDesc.group, '') + \ self._cmdVars[attr.attributeDesc.group] = self._cmdVars.get(attr.attributeDesc.group, '') + \
' ' + cmdVars[name] ' ' + self._cmdVars[name]
# For updating output attributes invalidation values # For updating output attributes invalidation values
cmdVarsNoCache = cmdVars.copy() cmdVarsNoCache = self._cmdVars.copy()
cmdVarsNoCache['cache'] = '' cmdVarsNoCache['cache'] = ''
# Evaluate output params # Evaluate output params
for name, attr in self._attributes.objects.items(): for name, attr in self._attributes.objects.items():
if attr.isInput: if attr.isInput:
continue # skip inputs continue # skip inputs
attr.value = attr.attributeDesc.value.format( attr.value = attr.attributeDesc.value.format(**self._cmdVars)
**cmdVars) attr._invalidationValue = attr.attributeDesc.value.format(**cmdVarsNoCache)
attr._invalidationValue = attr.attributeDesc.value.format(
**cmdVarsNoCache)
v = attr.getValueStr() v = attr.getValueStr()
cmdVars[name] = '--{name} {value}'.format(name=name, value=v) self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v)
cmdVars[name + 'Value'] = str(v) self._cmdVars[name + 'Value'] = str(v)
if v is not None and v is not '': if v is not None and v is not '':
cmdVars[attr.attributeDesc.group] = cmdVars.get(attr.attributeDesc.group, '') + \ self._cmdVars[attr.attributeDesc.group] = self._cmdVars.get(attr.attributeDesc.group, '') + \
' ' + cmdVars[name] ' ' + self._cmdVars[name]
@property @property
def isParallelized(self): def isParallelized(self):
@ -522,12 +528,15 @@ class Node(BaseObject):
else: else:
self._chunks[0].range = desc.Range() self._chunks[0].range = desc.Range()
def updateInternals(self): def updateInternals(self, cacheDir=None):
""" Update Node's internal parameters and output attributes. """ Update Node's internal parameters and output attributes.
This method is called when: This method is called when:
- an input parameter is modified - an input parameter is modified
- the graph main cache directory is changed - the graph main cache directory is changed
Args:
cacheDir (str): (optional) override graph's cache directory with custom path
""" """
# Update chunks splitting # Update chunks splitting
self._updateChunks() self._updateChunks()
@ -538,10 +547,11 @@ class Node(BaseObject):
folder = '' folder = ''
# Update command variables / output attributes # Update command variables / output attributes
self._cmdVars = { self._cmdVars = {
'cache': self.graph.cacheDir, 'cache': cacheDir or self.graph.cacheDir,
'nodeType': self.nodeType, 'nodeType': self.nodeType,
} }
self._buildCmdVars(self._cmdVars) self._computeUids()
self._buildCmdVars()
# Notify internal folder change if needed # Notify internal folder change if needed
if self.internalFolder != folder: if self.internalFolder != folder:
self.internalFolderChanged.emit() self.internalFolderChanged.emit()

View file

@ -110,15 +110,11 @@ class CameraInit(desc.CommandLineNode):
The updated views and intrinsics as two separate lists The updated views and intrinsics as two separate lists
""" """
assert isinstance(node.nodeDesc, CameraInit) assert isinstance(node.nodeDesc, CameraInit)
origCmdVars = node._cmdVars.copy() assert node.graph is None
# Python3: with tempfile.TemporaryDirectory(prefix="Meshroom_CameraInit") as tmpCache
tmpCache = tempfile.mkdtemp() tmpCache = tempfile.mkdtemp()
localCmdVars = { node.updateInternals(tmpCache)
'cache': tmpCache,
'nodeType': node.nodeType,
}
node._buildCmdVars(localCmdVars)
node._cmdVars = localCmdVars
try: try:
os.makedirs(os.path.join(tmpCache, node.internalFolder)) os.makedirs(os.path.join(tmpCache, node.internalFolder))
self.createViewpointsFile(node, additionalViews) self.createViewpointsFile(node, additionalViews)
@ -158,8 +154,6 @@ class CameraInit(desc.CommandLineNode):
except Exception: except Exception:
raise raise
finally: finally:
node._cmdVars = origCmdVars
node._buildCmdVars(localCmdVars)
shutil.rmtree(tmpCache) shutil.rmtree(tmpCache)
def createViewpointsFile(self, node, additionalViews=()): def createViewpointsFile(self, node, additionalViews=()):