mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-17 00:35:19 +02:00
[core] New dynamic output attributes
This commit is contained in:
parent
9a09310f07
commit
d5e356c0aa
6 changed files with 139 additions and 14 deletions
|
@ -686,6 +686,10 @@ class BaseNode(BaseObject):
|
|||
def minDepth(self):
|
||||
return self.graph.getDepth(self, minimal=True)
|
||||
|
||||
@property
|
||||
def valuesFile(self):
|
||||
return os.path.join(self.graph.cacheDir, self.internalFolder, 'values')
|
||||
|
||||
def getInputNodes(self, recursive, dependenciesOnly):
|
||||
return self.graph.getInputNodes(self, recursive=recursive, dependenciesOnly=dependenciesOnly)
|
||||
|
||||
|
@ -955,6 +959,7 @@ class BaseNode(BaseObject):
|
|||
}
|
||||
self._computeUids()
|
||||
self._buildCmdVars()
|
||||
self.updateOutputAttr()
|
||||
if self.nodeDesc:
|
||||
self.nodeDesc.postUpdate(self)
|
||||
# Notify internal folder change if needed
|
||||
|
@ -972,8 +977,11 @@ class BaseNode(BaseObject):
|
|||
"""
|
||||
Update node status based on status file content/existence.
|
||||
"""
|
||||
s = self.globalStatus
|
||||
for chunk in self._chunks:
|
||||
chunk.updateStatusFromCache()
|
||||
# logging.warning("updateStatusFromCache: {}, status: {} => {}".format(self.name, s, self.globalStatus))
|
||||
self.updateOutputAttr()
|
||||
|
||||
def submit(self, forceCompute=False):
|
||||
for chunk in self._chunks:
|
||||
|
@ -988,10 +996,71 @@ class BaseNode(BaseObject):
|
|||
def processIteration(self, iteration):
|
||||
self._chunks[iteration].process()
|
||||
|
||||
def preprocess(self):
|
||||
pass
|
||||
|
||||
def process(self, forceCompute=False):
|
||||
for chunk in self._chunks:
|
||||
chunk.process(forceCompute)
|
||||
|
||||
def postprocess(self):
|
||||
self.saveOutputAttr()
|
||||
|
||||
def updateOutputAttr(self):
|
||||
if not self.nodeDesc:
|
||||
return
|
||||
if not self.nodeDesc.hasDynamicOutputAttribute:
|
||||
return
|
||||
# logging.warning("updateOutputAttr: {}, status: {}".format(self.name, self.globalStatus))
|
||||
if self.getGlobalStatus() == Status.SUCCESS:
|
||||
self.loadOutputAttr()
|
||||
else:
|
||||
self.resetOutputAttr()
|
||||
|
||||
def resetOutputAttr(self):
|
||||
if not self.nodeDesc.hasDynamicOutputAttribute:
|
||||
return
|
||||
# logging.warning("resetOutputAttr: {}".format(self.name))
|
||||
for output in self.nodeDesc.outputs:
|
||||
if output.isDynamicValue:
|
||||
self.attribute(output.name).value = None
|
||||
|
||||
def loadOutputAttr(self):
|
||||
""" Load output attributes with dynamic values from a values.json file.
|
||||
"""
|
||||
if not self.nodeDesc.hasDynamicOutputAttribute:
|
||||
return
|
||||
valuesFile = self.valuesFile
|
||||
if not os.path.exists(valuesFile):
|
||||
logging.warning("No output attr file: {}".format(valuesFile))
|
||||
return
|
||||
|
||||
# logging.warning("load output attr: {}, value: {}".format(self.name, valuesFile))
|
||||
with open(valuesFile, 'r') as jsonFile:
|
||||
data = json.load(jsonFile)
|
||||
|
||||
# logging.warning(data)
|
||||
for output in self.nodeDesc.outputs:
|
||||
if output.isDynamicValue:
|
||||
self.attribute(output.name).value = data[output.name]
|
||||
|
||||
def saveOutputAttr(self):
|
||||
""" Save output attributes with dynamic values into a values.json file.
|
||||
"""
|
||||
if not self.nodeDesc.hasDynamicOutputAttribute:
|
||||
return
|
||||
data = {}
|
||||
for output in self.nodeDesc.outputs:
|
||||
if output.isDynamicValue:
|
||||
data[output.name] = self.attribute(output.name).value
|
||||
|
||||
valuesFile = self.valuesFile
|
||||
# logging.warning("save output attr: {}, value: {}".format(self.name, valuesFile))
|
||||
valuesFilepathWriting = getWritingFilepath(valuesFile)
|
||||
with open(valuesFilepathWriting, 'w') as jsonFile:
|
||||
json.dump(data, jsonFile, indent=4)
|
||||
renameWritingToFinalPath(valuesFilepathWriting, valuesFile)
|
||||
|
||||
def endSequence(self):
|
||||
pass
|
||||
|
||||
|
@ -1227,6 +1296,7 @@ class BaseNode(BaseObject):
|
|||
comment = Property(str, getComment, notify=internalAttributesChanged)
|
||||
internalFolderChanged = Signal()
|
||||
internalFolder = Property(str, internalFolder.fget, notify=internalFolderChanged)
|
||||
valuesFile = Property(str, valuesFile.fget, notify=internalFolderChanged)
|
||||
depthChanged = Signal()
|
||||
depth = Property(int, depth.fget, notify=depthChanged)
|
||||
minDepth = Property(int, minDepth.fget, notify=depthChanged)
|
||||
|
@ -1281,12 +1351,19 @@ class Node(BaseNode):
|
|||
for attrDesc in self.nodeDesc.internalInputs:
|
||||
self._internalAttributes.add(attributeFactory(attrDesc, kwargs.get(attrDesc.name, None), isOutput=False, node=self))
|
||||
|
||||
# List attributes per uid
|
||||
# Declare events for specific output attributes
|
||||
for attr in self._attributes:
|
||||
if attr.isOutput and attr.desc.semantic == "image":
|
||||
attr.enabledChanged.connect(self.outputAttrEnabledChanged)
|
||||
for uidIndex in attr.attributeDesc.uid:
|
||||
self.attributesPerUid[uidIndex].add(attr)
|
||||
|
||||
# List attributes per uid
|
||||
for attr in self._attributes:
|
||||
if attr.isInput:
|
||||
for uidIndex in attr.attributeDesc.uid:
|
||||
self.attributesPerUid[uidIndex].add(attr)
|
||||
else:
|
||||
if attr.attributeDesc.uid:
|
||||
logging.error(f"Output Attribute should not contain a UID: '{nodeType}.{attr.name}'")
|
||||
|
||||
# Add internal attributes with a UID to the list
|
||||
for attr in self._internalAttributes:
|
||||
|
@ -1347,7 +1424,7 @@ class Node(BaseNode):
|
|||
def toDict(self):
|
||||
inputs = {k: v.getExportValue() for k, v in self._attributes.objects.items() if v.isInput}
|
||||
internalInputs = {k: v.getExportValue() for k, v in self._internalAttributes.objects.items()}
|
||||
outputs = ({k: v.getExportValue() for k, v in self._attributes.objects.items() if v.isOutput})
|
||||
outputs = ({k: v.getExportValue() for k, v in self._attributes.objects.items() if v.isOutput and not v.desc.isDynamicValue})
|
||||
|
||||
return {
|
||||
'nodeType': self.nodeType,
|
||||
|
@ -1714,7 +1791,7 @@ def nodeFactory(nodeDict, name=None, template=False, uidConflict=False):
|
|||
# raising compatibility issues if their number differs: in that case, it is only useful
|
||||
# if some internal attributes do not exist or are invalid
|
||||
if not template and (sorted([attr.name for attr in nodeDesc.inputs if not isinstance(attr, desc.PushButtonParam)]) != sorted(inputs.keys()) or \
|
||||
sorted([attr.name for attr in nodeDesc.outputs]) != sorted(outputs.keys())):
|
||||
sorted([attr.name for attr in nodeDesc.outputs if not attr.isDynamicValue]) != sorted(outputs.keys())):
|
||||
compatibilityIssue = CompatibilityIssue.DescriptionConflict
|
||||
|
||||
# check whether there are any internal attributes that are invalidating in the node description: if there
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue