[core] compatibility : List of groups update is more flexible

This commit is contained in:
Grégoire De Lillo 2020-02-17 10:19:28 +01:00
parent 2e6990d2c6
commit 1f7663259a
2 changed files with 40 additions and 19 deletions

View file

@ -38,8 +38,13 @@ class Attribute(BaseObject):
"""
return value
def matchDescription(self, value):
""" Returns whether the value perfectly match attribute's description. """
def matchDescription(self, value, conform=False):
""" Returns whether the value perfectly match attribute's description.
Args:
value: the value
conform: try to adapt value to match the description
"""
try:
self.validateValue(value)
except ValueError:
@ -66,13 +71,13 @@ class ListAttribute(Attribute):
raise ValueError('ListAttribute only supports list/tuple input values (param:{}, value:{}, type:{})'.format(self.name, value, type(value)))
return value
def matchDescription(self, value):
def matchDescription(self, value, conform=False):
""" Check that 'value' content matches ListAttribute's element description. """
if not super(ListAttribute, self).matchDescription(value):
if not super(ListAttribute, self).matchDescription(value, conform):
return False
# list must be homogeneous: only test first element
if value:
return self._elementDesc.matchDescription(value[0])
return self._elementDesc.matchDescription(value[0], conform)
return True
@ -97,20 +102,32 @@ class GroupAttribute(Attribute):
raise ValueError('Value contains key that does not match group description : {}'.format(invalidKeys))
return value
def matchDescription(self, value):
def matchDescription(self, value, conform=False):
"""
Check that 'value' contains the exact same set of keys as GroupAttribute's group description
and that every child value match corresponding child attribute description.
Args:
value: the value
conform: remove entries that don't exist in the description.
"""
if not super(GroupAttribute, self).matchDescription(value):
return False
attrMap = {attr.name: attr for attr in self._groupDesc}
# must have the exact same child attributes
if sorted(value.keys()) != sorted(attrMap.keys()):
return False
if conform:
# remove invalid keys
invalidKeys = set(value.keys()).difference([attr.name for attr in self._groupDesc])
for k in invalidKeys:
del self._groupDesc[k]
else:
# must have the exact same child attributes
if sorted(value.keys()) != sorted(attrMap.keys()):
return False
for k, v in value.items():
# each child value must match corresponding child attribute description
if not attrMap[k].matchDescription(v):
if not attrMap[k].matchDescription(v, conform):
return False
return True

View file

@ -880,14 +880,9 @@ class CompatibilityNode(BaseNode):
self.splitCount = self.parallelization.get("split", 1)
self.setSize(self.parallelization.get("size", 1))
# inputs matching current type description
self._commonInputs = []
# create input attributes
for attrName, value in self._inputs.items():
matchDesc = self._addAttribute(attrName, value, False)
# store attributes that could be used during node upgrade
if matchDesc:
self._commonInputs.append(attrName)
self._addAttribute(attrName, value, False)
# create outputs attributes
for attrName, value in self.outputs.items():
@ -951,7 +946,7 @@ class CompatibilityNode(BaseNode):
return desc.StringParam(**params)
@staticmethod
def attributeDescFromName(refAttributes, name, value):
def attributeDescFromName(refAttributes, name, value, conform=False):
"""
Try to find a matching attribute description in refAttributes for given attribute 'name' and 'value'.
@ -968,8 +963,9 @@ class CompatibilityNode(BaseNode):
# 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)):
if attrDesc and (Attribute.isLinkExpression(value) or attrDesc.matchDescription(value, conform)):
return attrDesc
return None
def _addAttribute(self, name, val, isOutput):
@ -1043,8 +1039,16 @@ 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):
# 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 self._commonInputs})
**{key: value for key, value in self.inputs.items() if key in commonInputs})
compatibilityIssue = Property(int, lambda self: self.issue.value, constant=True)
canUpgrade = Property(bool, canUpgrade.fget, constant=True)