[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 return value
def matchDescription(self, value): def matchDescription(self, value, conform=False):
""" Returns whether the value perfectly match attribute's description. """ """ Returns whether the value perfectly match attribute's description.
Args:
value: the value
conform: try to adapt value to match the description
"""
try: try:
self.validateValue(value) self.validateValue(value)
except ValueError: 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))) raise ValueError('ListAttribute only supports list/tuple input values (param:{}, value:{}, type:{})'.format(self.name, value, type(value)))
return value return value
def matchDescription(self, value): def matchDescription(self, value, conform=False):
""" Check that 'value' content matches ListAttribute's element description. """ """ 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 return False
# list must be homogeneous: only test first element # list must be homogeneous: only test first element
if value: if value:
return self._elementDesc.matchDescription(value[0]) return self._elementDesc.matchDescription(value[0], conform)
return True return True
@ -97,20 +102,32 @@ class GroupAttribute(Attribute):
raise ValueError('Value contains key that does not match group description : {}'.format(invalidKeys)) raise ValueError('Value contains key that does not match group description : {}'.format(invalidKeys))
return value 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 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. 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): if not super(GroupAttribute, self).matchDescription(value):
return False return False
attrMap = {attr.name: attr for attr in self._groupDesc} attrMap = {attr.name: attr for attr in self._groupDesc}
# must have the exact same child attributes
if sorted(value.keys()) != sorted(attrMap.keys()): if conform:
return False # 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(): for k, v in value.items():
# each child value must match corresponding child attribute description # 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 False
return True return True

View file

@ -880,14 +880,9 @@ class CompatibilityNode(BaseNode):
self.splitCount = self.parallelization.get("split", 1) self.splitCount = self.parallelization.get("split", 1)
self.setSize(self.parallelization.get("size", 1)) self.setSize(self.parallelization.get("size", 1))
# inputs matching current type description
self._commonInputs = []
# create input attributes # create input attributes
for attrName, value in self._inputs.items(): for attrName, value in self._inputs.items():
matchDesc = self._addAttribute(attrName, value, False) self._addAttribute(attrName, value, False)
# store attributes that could be used during node upgrade
if matchDesc:
self._commonInputs.append(attrName)
# create outputs attributes # create outputs attributes
for attrName, value in self.outputs.items(): for attrName, value in self.outputs.items():
@ -951,7 +946,7 @@ class CompatibilityNode(BaseNode):
return desc.StringParam(**params) return desc.StringParam(**params)
@staticmethod @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'. 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: # consider this value matches description:
# - if it's a serialized link expression (no proper value to set/evaluate) # - if it's a serialized link expression (no proper value to set/evaluate)
# - or if it passes the 'matchDescription' test # - 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 attrDesc
return None return None
def _addAttribute(self, name, val, isOutput): def _addAttribute(self, name, val, isOutput):
@ -1043,8 +1039,16 @@ class CompatibilityNode(BaseNode):
if not self.canUpgrade: if not self.canUpgrade:
raise NodeUpgradeError(self.name, "no matching node type") raise NodeUpgradeError(self.name, "no matching node type")
# TODO: use upgrade method of node description if available # 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, 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) compatibilityIssue = Property(int, lambda self: self.issue.value, constant=True)
canUpgrade = Property(bool, canUpgrade.fget, constant=True) canUpgrade = Property(bool, canUpgrade.fget, constant=True)