From 1f7663259ad326195f987e6143731216fece4b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20De=20Lillo?= Date: Mon, 17 Feb 2020 10:19:28 +0100 Subject: [PATCH] [core] compatibility : List of groups update is more flexible --- meshroom/core/desc.py | 37 +++++++++++++++++++++++++++---------- meshroom/core/node.py | 22 +++++++++++++--------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index 07466d15f7..7618fa671f 100755 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -38,8 +38,13 @@ def validateValue(self, value): """ 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 @@ def validateValue(self, value): 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 @@ def validateValue(self, value): 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 diff --git a/meshroom/core/node.py b/meshroom/core/node.py index 0eeb13d402..8fc50d6606 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -880,14 +880,9 @@ def __init__(self, nodeType, nodeDict, position=None, issue=CompatibilityIssue.U 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 @@ def attributeDescFromValue(attrName, value, isOutput): 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 @@ def attributeDescFromName(refAttributes, name, value): # 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 @@ def upgrade(self): 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)