Adapt unittests to deal with graph saving

This commit is contained in:
Fabien Castan 2025-04-13 18:50:46 +02:00
parent cd219fd70e
commit 346d78df30
4 changed files with 45 additions and 31 deletions

View file

@ -167,6 +167,19 @@ def blockNodeCallbacks(func):
return inner return inner
def generateTempProjectFilepath(tmpFolder=None):
"""
Generate a temporary project filepath.
This method is used to generate a temporary project file for the current graph.
"""
from datetime import datetime
if tmpFolder is None:
from meshroom.env import EnvVar
tmpFolder = EnvVar.get(EnvVar.MESHROOM_TEMP_PATH)
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
return os.path.join(tmpFolder, f"meshroom_{timestamp}.mg")
class Graph(BaseObject): class Graph(BaseObject):
""" """
_________________ _________________ _________________ _________________ _________________ _________________
@ -1316,7 +1329,7 @@ class Graph(BaseObject):
def _save(self, filepath=None, setupProjectFile=True, template=False): def _save(self, filepath=None, setupProjectFile=True, template=False):
path = filepath or self._filepath path = filepath or self._filepath
if not path: if not path:
raise ValueError("filepath must be specified for unsaved files.") path = generateTempProjectFilepath()
data = self.serialize(template) data = self.serialize(template)
@ -1329,6 +1342,21 @@ class Graph(BaseObject):
# update the file date version # update the file date version
self._fileDateVersion = os.path.getmtime(path) self._fileDateVersion = os.path.getmtime(path)
def saveAsTemp(self, tmpFolder=None):
"""
Save the current Meshroom graph as a temporary project file.
"""
# Update the saving flag indicating that the current graph is being saved
self._saving = True
try:
self._saveAsTemp(tmpFolder)
finally:
self._saving = False
def _saveAsTemp(self, tmpFolder=None):
projectPath = generateTempProjectFilepath(tmpFolder)
self._save(projectPath)
def _setFilepath(self, filepath): def _setFilepath(self, filepath):
""" """
Set the internal filepath of this Graph. Set the internal filepath of this Graph.
@ -1594,6 +1622,8 @@ def executeGraph(graph, toNodes=None, forceCompute=False, forceStatus=False):
print('Nodes to execute: ', str([n.name for n in nodes])) print('Nodes to execute: ', str([n.name for n in nodes]))
graph.save()
for node in nodes: for node in nodes:
node.beginSequence(forceCompute) node.beginSequence(forceCompute)

View file

@ -24,7 +24,7 @@ from PySide6.QtCore import (
from meshroom.core import sessionUid from meshroom.core import sessionUid
from meshroom.common.qt import QObjectListModel from meshroom.common.qt import QObjectListModel
from meshroom.core.attribute import Attribute, ListAttribute from meshroom.core.attribute import Attribute, ListAttribute
from meshroom.core.graph import Graph, Edge from meshroom.core.graph import Graph, Edge, generateTempProjectFilepath
from meshroom.core.graphIO import GraphIO from meshroom.core.graphIO import GraphIO
from meshroom.core.taskManager import TaskManager from meshroom.core.taskManager import TaskManager
@ -516,11 +516,8 @@ class UIGraph(QObject):
@Slot() @Slot()
def saveAsTemp(self): def saveAsTemp(self):
from meshroom.env import EnvVar projectPath = generateTempProjectFilepath()
from datetime import datetime self._saveAs(projectPath)
tempFolder = EnvVar.get(EnvVar.MESHROOM_TEMP_PATH)
timestamp = datetime.now().strftime("%Y-%m-%d_%H:%M")
self._saveAs(os.path.join(tempFolder, f"meshroom_{timestamp}.mg"))
@Slot() @Slot()
def save(self): def save(self):

View file

@ -6,19 +6,6 @@ import pytest
from meshroom.core.graph import Graph from meshroom.core.graph import Graph
@pytest.fixture
def graphWithIsolatedCache():
"""
Yield a Graph instance using a unique temporary cache directory.
Can be used for testing graph computation in isolation, without having to save the graph to disk.
"""
with tempfile.TemporaryDirectory() as cacheDir:
graph = Graph("")
graph.cacheDir = cacheDir
yield graph
@pytest.fixture @pytest.fixture
def graphSavedOnDisk(): def graphSavedOnDisk():
""" """
@ -27,6 +14,6 @@ def graphSavedOnDisk():
Can be used for testing graph IO and computation in isolation. Can be used for testing graph IO and computation in isolation.
""" """
with tempfile.TemporaryDirectory() as cacheDir: with tempfile.TemporaryDirectory() as cacheDir:
graph = Graph("") graph = Graph()
graph.save(Path(cacheDir) / "test_graph.mg") graph.saveAsTemp(cacheDir)
yield graph yield graph

View file

@ -5,7 +5,7 @@ from meshroom.core import desc, registerNodeType, unregisterNodeType
from meshroom.core.node import Node from meshroom.core.node import Node
class NodeWithAttributeChangedCallback(desc.Node): class NodeWithAttributeChangedCallback(desc.BaseNode):
""" """
A Node containing an input Attribute with an 'on{Attribute}Changed' method, A Node containing an input Attribute with an 'on{Attribute}Changed' method,
called whenever the value of this attribute is changed explicitly. called whenever the value of this attribute is changed explicitly.
@ -182,7 +182,7 @@ class TestAttributeCallbackTriggerInGraph:
assert loadedNodeB.affectedInput.value == 2 assert loadedNodeB.affectedInput.value == 2
class NodeWithCompoundAttributes(desc.Node): class NodeWithCompoundAttributes(desc.BaseNode):
""" """
A Node containing a variation of compound attributes (List/Groups), A Node containing a variation of compound attributes (List/Groups),
called whenever the value of this attribute is changed explicitly. called whenever the value of this attribute is changed explicitly.
@ -311,7 +311,7 @@ class TestAttributeCallbackBehaviorWithUpstreamCompoundAttributes:
assert nodeB.affectedInput.value == 20 assert nodeB.affectedInput.value == 20
class NodeWithDynamicOutputValue(desc.Node): class NodeWithDynamicOutputValue(desc.BaseNode):
""" """
A Node containing an output attribute which value is computed dynamically during graph execution. A Node containing an output attribute which value is computed dynamically during graph execution.
""" """
@ -363,9 +363,9 @@ class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
assert nodeB.affectedInput.value == 0 assert nodeB.affectedInput.value == 0
def test_connectingComputedDynamicOutputTriggersDownstreamAttributeChangedCallback( def test_connectingComputedDynamicOutputTriggersDownstreamAttributeChangedCallback(
self, graphWithIsolatedCache self, graphSavedOnDisk
): ):
graph: Graph = graphWithIsolatedCache graph: Graph = graphSavedOnDisk
nodeA = graph.addNewNode(NodeWithDynamicOutputValue.__name__) nodeA = graph.addNewNode(NodeWithDynamicOutputValue.__name__)
nodeB = graph.addNewNode(NodeWithAttributeChangedCallback.__name__) nodeB = graph.addNewNode(NodeWithAttributeChangedCallback.__name__)
@ -377,9 +377,9 @@ class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
assert nodeB.affectedInput.value == 40 assert nodeB.affectedInput.value == 40
def test_dynamicOutputValueComputeDoesNotTriggerDownstreamAttributeChangedCallback( def test_dynamicOutputValueComputeDoesNotTriggerDownstreamAttributeChangedCallback(
self, graphWithIsolatedCache self, graphSavedOnDisk
): ):
graph: Graph = graphWithIsolatedCache graph: Graph = graphSavedOnDisk
nodeA = graph.addNewNode(NodeWithDynamicOutputValue.__name__) nodeA = graph.addNewNode(NodeWithDynamicOutputValue.__name__)
nodeB = graph.addNewNode(NodeWithAttributeChangedCallback.__name__) nodeB = graph.addNewNode(NodeWithAttributeChangedCallback.__name__)
@ -392,9 +392,9 @@ class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
def test_clearingDynamicOutputValueDoesNotTriggerDownstreamAttributeChangedCallback( def test_clearingDynamicOutputValueDoesNotTriggerDownstreamAttributeChangedCallback(
self, graphWithIsolatedCache self, graphSavedOnDisk
): ):
graph: Graph = graphWithIsolatedCache graph: Graph = graphSavedOnDisk
nodeA = graph.addNewNode(NodeWithDynamicOutputValue.__name__) nodeA = graph.addNewNode(NodeWithDynamicOutputValue.__name__)
nodeB = graph.addNewNode(NodeWithAttributeChangedCallback.__name__) nodeB = graph.addNewNode(NodeWithAttributeChangedCallback.__name__)