Skip to content

Commit

Permalink
Merge pull request #2059 from alicevision/dev/uidCompatibility
Browse files Browse the repository at this point in the history
[core] Detect and handle UID conflicts when loading a graph
  • Loading branch information
mugulmd authored Jun 16, 2023
2 parents 61c96a8 + 91b6045 commit 90c562f
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
33 changes: 32 additions & 1 deletion meshroom/core/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def fileFeatures(self):
@Slot(str)
def load(self, filepath, setupProjectFile=True, importProject=False, publishOutputs=False):
"""
Load a meshroom graph ".mg" file.
Load a Meshroom graph ".mg" file.
Args:
filepath: project filepath to load
Expand Down Expand Up @@ -308,8 +308,39 @@ def load(self, filepath, setupProjectFile=True, importProject=False, publishOutp
# Note: needs to be done at the end as it will trigger an updateInternals.
self._setFilepath(filepath)

# By this point, the graph has been fully loaded and an updateInternals has been triggered, so all the nodes'
# links have been resolved and their UID computations are all complete.
# It is now possible to check whether the UIDs stored in the graph file for each node correspond to the ones
# that were computed.
if not isTemplate: # UIDs are not stored in templates
self._evaluateUidConflicts(graphData)
self._applyExpr()

return True

def _evaluateUidConflicts(self, data):
"""
Compare the UIDs of all the nodes in the graph with the UID that is expected in the graph file. If there
are mismatches, the nodes with the unexpected UID are replaced with "UidConflict" compatibility nodes.
Args:
data (dict): the dictionary containing all the nodes to import and their data
"""
for nodeName, nodeData in sorted(data.items(), key=lambda x: self.getNodeIndexFromName(x[0])):
node = self.node(nodeName)
# If the node is a CompatibilityNode, its UID is not available and there is no need to check it
if isinstance(node, CompatibilityNode):
continue

savedUid = nodeData.get("uids", "").get("0", "") # Node's UID from the graph file
graphUid = node._uids.get(0) # Node's UID from the graph itself
if savedUid != graphUid and graphUid is not None:
# Different UIDs, remove the existing node from the graph and replace it with a CompatibilityNode
logging.debug("UID conflict detected for {}".format(nodeName))
self.removeNode(nodeName)
n = nodeFactory(nodeData, nodeName, template=False, uidConflict=True)
self._addNode(n, nodeName)

def updateImportedProject(self, data):
"""
Update the names and links of the project to import so that it can fit
Expand Down
11 changes: 9 additions & 2 deletions meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1487,6 +1487,8 @@ def issueDetails(self):
)
elif self.issue == CompatibilityIssue.DescriptionConflict:
return "Node attributes do not match node description."
elif self.issue == CompatibilityIssue.UidConflict:
return "Node UID differs from the expected one."
else:
return "Unknown error."

Expand Down Expand Up @@ -1577,7 +1579,7 @@ def upgrade(self):
issueDetails = Property(str, issueDetails.fget, constant=True)


def nodeFactory(nodeDict, name=None, template=False):
def nodeFactory(nodeDict, name=None, template=False, uidConflict=False):
"""
Create a node instance by deserializing the given node data.
If the serialized data matches the corresponding node type description, a Node instance is created.
Expand All @@ -1586,6 +1588,8 @@ def nodeFactory(nodeDict, name=None, template=False):
Args:
nodeDict (dict): the serialization of the node
name (str): (optional) the node's name
template (bool): (optional) true if the node is part of a template, false otherwise
uidConflict (bool): (optional) true if a UID conflict has been detected externally on that node
Returns:
BaseNode: the created node
Expand Down Expand Up @@ -1614,7 +1618,10 @@ def nodeFactory(nodeDict, name=None, template=False):
# unknown node type
compatibilityIssue = CompatibilityIssue.UnknownNodeType

if nodeDesc:
if uidConflict:
compatibilityIssue = CompatibilityIssue.UidConflict

if nodeDesc and not uidConflict: # if uidConflict, there is no need to look for another compatibility issue
# compare serialized node version with current node version
currentNodeVersion = meshroom.core.nodeVersion(nodeDesc)
# if both versions are available, check for incompatibility in major version
Expand Down
4 changes: 2 additions & 2 deletions meshroom/ui/qml/GraphEditor/CompatibilityManager.qml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ MessageDialog {
// alias to underlying compatibilityNodes model
readonly property var nodesModel: uigraph ? uigraph.graph.compatibilityNodes : undefined
// the total number of compatibility issues
readonly property int issueCount: (nodesModel != undefined) ? nodesModel.count : 0
readonly property int issueCount: (nodesModel !== undefined && nodesModel !== null) ? nodesModel.count : 0
// the number of CompatibilityNodes that can be upgraded
readonly property int upgradableCount: {
var count = 0
Expand Down Expand Up @@ -113,7 +113,7 @@ MessageDialog {

Label {
id: questionLabel
text: upgradableCount ? "Upgrade all possible nodes to current version ?"
text: upgradableCount ? "Upgrade all possible nodes to current version?"
: "Those nodes can't be upgraded, remove them manually if needed."
}
}
Expand Down

0 comments on commit 90c562f

Please sign in to comment.