[core] Improve project files upgrade

- upgrade groups with changes in params
- new upgradeAttributeValues per node
This commit is contained in:
Fabien Castan 2021-08-13 12:00:33 +02:00
parent f1331c6a15
commit 5ab6ed8e52
5 changed files with 149 additions and 51 deletions

View file

@ -1084,11 +1084,27 @@ class Node(BaseNode):
for uidIndex in attr.attributeDesc.uid:
self.attributesPerUid[uidIndex].add(attr)
self.setAttributeValues(kwargs)
def setAttributeValues(self, values):
# initialize attribute values
for k, v in kwargs.items():
for k, v in values.items():
attr = self.attribute(k)
if attr.isInput:
self.attribute(k).value = v
attr.value = v
def upgradeAttributeValues(self, values):
# initialize attribute values
for k, v in values.items():
if not self.hasAttribute(k):
# skip missing attributes
continue
attr = self.attribute(k)
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}
@ -1157,9 +1173,10 @@ class CompatibilityNode(BaseNode):
# make a deepcopy of nodeDict to handle CompatibilityNode duplication
# and be able to change modified inputs (see CompatibilityNode.toDict)
self.nodeDict = copy.deepcopy(nodeDict)
self.version = Version(self.nodeDict.get("version", None))
self._inputs = nodeDict.get("inputs", {})
self.outputs = nodeDict.get("outputs", {})
self._inputs = self.nodeDict.get("inputs", {})
self.outputs = self.nodeDict.get("outputs", {})
self._internalFolder = self.nodeDict.get("internalFolder", "")
self._uids = self.nodeDict.get("uids", {})
@ -1237,7 +1254,7 @@ class CompatibilityNode(BaseNode):
return desc.StringParam(**params)
@staticmethod
def attributeDescFromName(refAttributes, name, value, conform=False):
def attributeDescFromName(refAttributes, name, value, strict=True):
"""
Try to find a matching attribute description in refAttributes for given attribute 'name' and 'value'.
@ -1245,16 +1262,24 @@ class CompatibilityNode(BaseNode):
refAttributes ([desc.Attribute]): reference Attributes to look for a description
name (str): attribute's name
value: attribute's value
strict: strict test for the match (for instance, regarding a group with some parameter changes)
Returns:
desc.Attribute: an attribute description from refAttributes if a match is found, None otherwise.
"""
# from original node description based on attribute's name
attrDesc = next((d for d in refAttributes if d.name == name), None)
# consider this value matches description:
# - if it's a serialized link expression (no proper value to set/evaluate)
# - or if it passes the 'matchDescription' test
if attrDesc and (Attribute.isLinkExpression(value) or attrDesc.matchDescription(value, conform)):
if attrDesc is None:
return None
# We have found a description, and we still need to
# check if the value matches the attribute description.
#
# If it is a serialized link expression (no proper value to set/evaluate)
if Attribute.isLinkExpression(value):
return attrDesc
# If it passes the 'matchDescription' test
if attrDesc.matchDescription(value, strict):
return attrDesc
return None
@ -1285,13 +1310,13 @@ class CompatibilityNode(BaseNode):
@property
def issueDetails(self):
if self.issue == CompatibilityIssue.UnknownNodeType:
return "Unknown node type: {}.".format(self.nodeType)
return "Unknown node type: '{}'.".format(self.nodeType)
elif self.issue == CompatibilityIssue.VersionConflict:
return "Node version '{}' conflicts with current version '{}'.".format(
self.nodeDict["version"], nodeVersion(self.nodeDesc)
)
elif self.issue == CompatibilityIssue.DescriptionConflict:
return "Node attributes don't match node description."
return "Node attributes do not match node description."
else:
return "Unknown error."
@ -1329,17 +1354,30 @@ class CompatibilityNode(BaseNode):
"""
if not self.canUpgrade:
raise NodeUpgradeError(self.name, "no matching node type")
# TODO: use upgrade method of node description if available
# inputs matching current type description
commonInputs = []
for attrName, value in self._inputs.items():
if self.attributeDescFromName(self.nodeDesc.inputs, attrName, value, conform=True):
if self.attributeDescFromName(self.nodeDesc.inputs, attrName, value, strict=False):
# store attributes that could be used during node upgrade
commonInputs.append(attrName)
return Node(self.nodeType, position=self.position,
**{key: value for key, value in self.inputs.items() if key in commonInputs})
node = Node(self.nodeType, position=self.position)
attrValues = {key: value for key, value in self.inputs.items() if key in commonInputs}
# Use upgrade method of the node description itself if available
try:
upgradedAttrValues = node.nodeDesc.upgradeAttributeValues(attrValues, self.version)
except Exception as e:
logging.error("Error in the upgrade implementation of the node: {}.\n{}".format(self.name, str(e)))
upgradedAttrValues = attrValues
if not isinstance(upgradedAttrValues, dict):
logging.error("Error in the upgrade implementation of the node: {}. The return type is incorrect.".format(self.name))
upgradedAttrValues = attrValues
node.upgradeAttributeValues(upgradedAttrValues)
return node
compatibilityIssue = Property(int, lambda self: self.issue.value, constant=True)
canUpgrade = Property(bool, canUpgrade.fget, constant=True)