From fd0c2098378f30c62bc7cfe58e7bf8eff1878218 Mon Sep 17 00:00:00 2001 From: Yann Lanthony Date: Tue, 17 Oct 2017 16:32:42 +0200 Subject: [PATCH 1/2] [commands] only re-create out edges when undoing RemoveNode "in" edges are automatically recreated since serialized as a connection expression in Node's dict representation and resolved by addNode --- meshroom/core/graph.py | 13 +++++++++---- meshroom/ui/commands.py | 17 ++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/meshroom/core/graph.py b/meshroom/core/graph.py index 2d8b789c..5a089fc3 100644 --- a/meshroom/core/graph.py +++ b/meshroom/core/graph.py @@ -589,20 +589,25 @@ class Graph(BaseObject): return [edge for edge in self.edges if edge.src == attribute] def removeNode(self, nodeName): + """ + Remove the node identified by 'nodeName' from the graph + and return in and out edges removed by this operation in two dicts {dstAttr.fullName(), srcAttr.fullName()} + """ node = self.node(nodeName) self._nodes.pop(nodeName) - edges = {} + inEdges = {} + outEdges = {} for attr in node._attributes: for edge in self.outEdges(attr): self.edges.remove(edge) - edges[edge.dst.fullName()] = edge.src.fullName() + outEdges[edge.dst.fullName()] = edge.src.fullName() if attr in self.edges.keys(): edge = self.edges.pop(attr) - edges[edge.dst.fullName()] = edge.src.fullName() + inEdges[edge.dst.fullName()] = edge.src.fullName() self.updateInternals() - return edges + return inEdges, outEdges @Slot(str, result=Node) def addNewNode(self, nodeType, **kwargs): diff --git a/meshroom/ui/commands.py b/meshroom/ui/commands.py index d5964acf..71608434 100644 --- a/meshroom/ui/commands.py +++ b/meshroom/ui/commands.py @@ -90,24 +90,23 @@ class AddNodeCommand(GraphCommand): class RemoveNodeCommand(GraphCommand): def __init__(self, graph, node, parent=None): super(RemoveNodeCommand, self).__init__(graph, parent) - self.nodeDesc = node.toDict() + self.nodeDict = node.toDict() self.nodeName = node.getName() self.setText("Remove Node {}".format(self.nodeName)) - self.edges = {} + self.outEdges = {} def redoImpl(self): - self.edges = self.graph.removeNode(self.nodeName) + # only keep outEdges since inEdges are serialized in nodeDict + inEdges, self.outEdges = self.graph.removeNode(self.nodeName) return True def undoImpl(self): - node = self.graph.addNode(Node(nodeDesc=self.nodeDesc["nodeType"], - parent=self.graph, **self.nodeDesc["attributes"] + node = self.graph.addNode(Node(nodeDesc=self.nodeDict["nodeType"], + parent=self.graph, **self.nodeDict["attributes"] ), self.nodeName) assert (node.getName() == self.nodeName) - # recreate edges deleted on node removal - # edges having this node as destination could be retrieved from node description - # but we're missing edges starting from this node - for key, value in self.edges.items(): + # recreate out edges deleted on node removal + for key, value in self.outEdges.items(): dstNode, dstAttr = key.split(".") srcNode, srcAttr = value.split(".") self.graph.addEdge(self.graph.node(srcNode).attribute(srcAttr), From e49fdf457cb65d0acd2effc01a779e162f7338ec Mon Sep 17 00:00:00 2001 From: Yann Lanthony Date: Tue, 17 Oct 2017 16:43:54 +0200 Subject: [PATCH 2/2] [core] reset status of submitted nodes when a node computation fails * catch Exception and stop graph execution * report error using logging.error * misc: fix indentation issues --- meshroom/core/graph.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/meshroom/core/graph.py b/meshroom/core/graph.py index 5a089fc3..21321e48 100644 --- a/meshroom/core/graph.py +++ b/meshroom/core/graph.py @@ -11,6 +11,7 @@ import uuid from collections import defaultdict from enum import Enum # available by default in python3. For python2: "pip install enum34" from pprint import pprint +import logging from . import stats from meshroom import core as pg @@ -445,19 +446,18 @@ class Node(BaseObject): self.status.returnCode = self._subprocess.returncode if self._subprocess.returncode != 0: - logContent = '' with open(self.logFile(), 'r') as logF: logContent = ''.join(logF.readlines()) self.upgradeStatusTo(Status.ERROR) raise RuntimeError('Error on node "{}":\nLog:\n{}'.format(self.name, logContent)) - except: + except Exception: self.upgradeStatusTo(Status.ERROR) raise finally: - elapsedTime = time.time() - startTime - print(' - elapsed time:', elapsedTime) + elapsedTime = time.time() - startTime + print(' - elapsed time:', elapsedTime) self._subprocess = None - # ask and wait for the stats thread to terminate + # ask and wait for the stats thread to stop statThread.stopRequest() statThread.join() @@ -793,6 +793,14 @@ class Graph(BaseObject): """ Request graph execution to be stopped """ self.stopExecutionRequested.emit() + def submittedNodes(self): + """ Return the list of submitted nodes inside this Graph """ + return [node for node in self.nodes if node.isAlreadySubmitted()] + + def clearSubmittedNodes(self): + """ Reset the status of already submitted nodes to Status.NONE """ + [node.upgradeStatusTo(Status.NONE) for node in self.submittedNodes()] + @property def nodes(self): return self._nodes @@ -848,8 +856,13 @@ def execute(graph, toNodes=None, force=False): node.beginSequence() for i, node in enumerate(nodes): - print('\n[{i}/{N}] {nodeName}'.format(i=i+1, N=len(nodes), nodeName=node.nodeType())) - node.process() + try: + print('\n[{i}/{N}] {nodeName}'.format(i=i + 1, N=len(nodes), nodeName=node.nodeType)) + node.process() + except Exception as e: + logging.error("Error on node computation: {}".format(e)) + graph.clearSubmittedNodes() + return for node in nodes: node.endSequence()