Skip to content

Commit

Permalink
[core] load internalAttributes in compatibility mode
Browse files Browse the repository at this point in the history
  • Loading branch information
cbentejac committed Aug 31, 2022
1 parent 1387090 commit 40e6783
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 12 deletions.
72 changes: 60 additions & 12 deletions meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,12 @@ def internalAttribute(self, name):
# The internal attribute itself can be returned directly
return self._internalAttributes.get(name)

def setInternalAttributeValues(self, values):
# initialize internal attribute values
for k, v in values.items():
attr = self.internalAttribute(k)
attr.value = v

def getAttributes(self):
return self._attributes

Expand Down Expand Up @@ -1148,11 +1154,18 @@ def upgradeAttributeValues(self, values):
except ValueError:
pass

def setInternalAttributeValues(self, values):
# initialize internal attribute values
def upgradeInternalAttributeValues(self, values):
# initialize internal attibute values
for k, v in values.items():
if not self.hasInternalAttribute(k):
# skip missing atributes
continue
attr = self.internalAttribute(k)
attr.value = v
if attr.isInput:
try:
attr.upgradeValue(v)
except ValueError:
pass

def toDict(self):
inputs = {k: v.getExportValue() for k, v in self._attributes.objects.items() if v.isInput}
Expand Down Expand Up @@ -1226,6 +1239,7 @@ def __init__(self, nodeType, nodeDict, position=None, issue=CompatibilityIssue.U
self.version = Version(self.nodeDict.get("version", None))

self._inputs = self.nodeDict.get("inputs", {})
self._internalInputs = self.nodeDict.get("internalInputs", {})
self.outputs = self.nodeDict.get("outputs", {})
self._internalFolder = self.nodeDict.get("internalFolder", "")
self._uids = self.nodeDict.get("uids", {})
Expand All @@ -1237,11 +1251,15 @@ def __init__(self, nodeType, nodeDict, position=None, issue=CompatibilityIssue.U

# create input attributes
for attrName, value in self._inputs.items():
self._addAttribute(attrName, value, False)
self._addAttribute(attrName, value, isOutput=False)

# create outputs attributes
for attrName, value in self.outputs.items():
self._addAttribute(attrName, value, True)
self._addAttribute(attrName, value, isOutput=True)

# create internal attributes
for attrName, value in self._internalInputs.items():
self._addAttribute(attrName, value, isOutput=False, internalAttr=True)

# create NodeChunks matching serialized parallelization settings
self._chunks.setObjectList([
Expand Down Expand Up @@ -1334,7 +1352,7 @@ def attributeDescFromName(refAttributes, name, value, strict=True):

return None

def _addAttribute(self, name, val, isOutput):
def _addAttribute(self, name, val, isOutput, internalAttr=False):
"""
Add a new attribute on this node.
Expand All @@ -1348,13 +1366,19 @@ def _addAttribute(self, name, val, isOutput):
"""
attrDesc = None
if self.nodeDesc:
refAttrs = self.nodeDesc.outputs if isOutput else self.nodeDesc.inputs
if internalAttr:
refAttrs = self.nodeDesc.internalInputs
else:
refAttrs = self.nodeDesc.outputs if isOutput else self.nodeDesc.inputs
attrDesc = CompatibilityNode.attributeDescFromName(refAttrs, name, val)
matchDesc = attrDesc is not None
if not matchDesc:
if attrDesc is None:
attrDesc = CompatibilityNode.attributeDescFromValue(name, val, isOutput)
attribute = attributeFactory(attrDesc, val, isOutput, self)
self._attributes.add(attribute)
if internalAttr:
self._internalAttributes.add(attribute)
else:
self._attributes.add(attribute)
return matchDesc

@property
Expand All @@ -1379,6 +1403,13 @@ def inputs(self):
return self._inputs
return {k: v.getExportValue() for k, v in self._attributes.objects.items() if v.isInput}

@property
def internalInputs(self):
""" Get current node's internal attributes """
if not self.graph:
return self._internalInputs
return {k: v.getExportValue() for k, v in self._internalAttributes.objects.items()}

def toDict(self):
"""
Return the original serialized node that generated a compatibility issue.
Expand Down Expand Up @@ -1412,9 +1443,16 @@ def upgrade(self):
# store attributes that could be used during node upgrade
commonInputs.append(attrName)

commonInternalAttributes = []
for attrName, value in self._internalInputs.items():
if self.attributeDescFromName(self.nodeDesc.internalInputs, attrName, value, strict=False):
# store internal attributes that could be used during node upgrade
commonInternalAttributes.append(attrName)

node = Node(self.nodeType, position=self.position)
# convert attributes from a list of tuples into a dict
attrValues = {key: value for (key, value) in self.inputs.items()}
intAttrValues = {key: value for (key, value) in self.internalInputs.items()}

# Use upgrade method of the node description itself if available
try:
Expand All @@ -1427,9 +1465,15 @@ def upgrade(self):
logging.error("Error in the upgrade implementation of the node: {}. The return type is incorrect.".format(self.name))
upgradedAttrValues = attrValues

upgradedAttrValuesTmp = {key: value for (key, value) in upgradedAttrValues.items() if key in commonInputs}

node.upgradeAttributeValues(upgradedAttrValues)

try:
upgradedIntAttrValues = node.nodeDesc.upgradeAttributeValues(intAttrValues, self.version)
except Exception as e:
logging.error("Error in the upgrade implementation of the node: {}.\n{]".format(self.name, str(e)))
upgradedIntAttrValues = intAttrValues

node.upgradeInternalAttributeValues(upgradedIntAttrValues)
return node

compatibilityIssue = Property(int, lambda self: self.issue.value, constant=True)
Expand Down Expand Up @@ -1482,10 +1526,14 @@ def nodeFactory(nodeDict, name=None):
compatibilityIssue = CompatibilityIssue.VersionConflict
# in other cases, check attributes compatibility between serialized node and its description
else:
# check that the node has the exact same set of inputs/outputs as its description
# check that the node has the exact same set of inputs/outputs as its description;
# do not perform that check for internal attributes because there is no point in
# 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 sorted([attr.name for attr in nodeDesc.inputs]) != sorted(inputs.keys()) or \
sorted([attr.name for attr in nodeDesc.outputs]) != sorted(outputs.keys()):
compatibilityIssue = CompatibilityIssue.DescriptionConflict

# verify that all inputs match their descriptions
for attrName, value in inputs.items():
if not CompatibilityNode.attributeDescFromName(nodeDesc.inputs, attrName, value):
Expand Down
2 changes: 2 additions & 0 deletions meshroom/ui/qml/GraphEditor/NodeEditor.qml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Panel {
currentIndex: tabBar.currentIndex

AttributeEditor {
id: inOutAttr
Layout.fillHeight: true
Layout.fillWidth: true
model: root.node.attributes
Expand Down Expand Up @@ -187,6 +188,7 @@ Panel {
}

AttributeEditor {
id: nodeInternalAttr
Layout.fillHeight: true
Layout.fillWidth: true
model: root.node.internalAttributes
Expand Down

0 comments on commit 40e6783

Please sign in to comment.