[tests] Use the NodePluginManager instance in the unit tests

The plugin manager is now effectively used for all the operations that
involve registering or unregistering nodes.
This commit is contained in:
Candice Bentéjac 2025-05-12 17:33:02 +02:00
parent 28042dd2ad
commit 777ed4207e
8 changed files with 103 additions and 63 deletions

View file

@ -1,8 +1,13 @@
import os import os
from meshroom.core import loadAllNodes, initPipelines from meshroom.core import loadAllNodes
from meshroom.core import pluginManager
plugins = loadAllNodes(os.path.join(os.path.dirname(__file__), "nodes"))
for plugin in plugins:
pluginManager.addPlugin(plugin)
pluginManager.registerPlugin(plugin.name)
loadAllNodes(os.path.join(os.path.dirname(__file__), "nodes"))
if os.getenv("MESHROOM_PIPELINE_TEMPLATES_PATH", False): if os.getenv("MESHROOM_PIPELINE_TEMPLATES_PATH", False):
os.environ["MESHROOM_PIPELINE_TEMPLATES_PATH"] += os.pathsep + os.path.dirname(os.path.realpath(__file__)) os.environ["MESHROOM_PIPELINE_TEMPLATES_PATH"] += os.pathsep + os.path.dirname(os.path.realpath(__file__))
else: else:

View file

@ -1,4 +1,5 @@
from meshroom.core import desc, registerNodeType, unregisterNodeType from meshroom.core import desc, pluginManager
from meshroom.core.plugins import NodePlugin
from meshroom.core.graph import Graph, loadGraph from meshroom.core.graph import Graph, loadGraph
@ -52,13 +53,15 @@ class NodeWithChoiceParamsSavingValuesOverride(desc.Node):
class TestChoiceParam: class TestChoiceParam:
nodePlugin = NodePlugin(NodeWithChoiceParams)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithChoiceParams) pluginManager.registerNode(cls.nodePlugin)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithChoiceParams) pluginManager.unregisterNode(cls.nodePlugin)
def test_customValueIsSerialized(self, graphSavedOnDisk): def test_customValueIsSerialized(self, graphSavedOnDisk):
graph: Graph = graphSavedOnDisk graph: Graph = graphSavedOnDisk
@ -117,13 +120,15 @@ class TestChoiceParam:
class TestChoiceParamSavingCustomValues: class TestChoiceParamSavingCustomValues:
nodePlugin = NodePlugin(NodeWithChoiceParamsSavingValuesOverride)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithChoiceParamsSavingValuesOverride) pluginManager.registerNode(cls.nodePlugin)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithChoiceParamsSavingValuesOverride) pluginManager.unregisterNode(cls.nodePlugin)
def test_customValueIsSerialized(self, graphSavedOnDisk): def test_customValueIsSerialized(self, graphSavedOnDisk):
graph: Graph = graphSavedOnDisk graph: Graph = graphSavedOnDisk
@ -166,4 +171,4 @@ class TestChoiceParamSavingCustomValues:
loadedNodeA = loadedGraph.node(nodeA.name) loadedNodeA = loadedGraph.node(nodeA.name)
loadedNodeB = loadedGraph.node(nodeB.name) loadedNodeB = loadedGraph.node(nodeB.name)
assert loadedNodeB.choice.linkParam == loadedNodeA.choice assert loadedNodeB.choice.linkParam == loadedNodeA.choice
assert loadedNodeB.choiceMulti.linkParam == loadedNodeA.choiceMulti assert loadedNodeB.choiceMulti.linkParam == loadedNodeA.choiceMulti

View file

@ -7,8 +7,8 @@ import copy
from typing import Type from typing import Type
import pytest import pytest
import meshroom.core from meshroom.core import desc, pluginManager
from meshroom.core import desc, registerNodeType, unregisterNodeType from meshroom.core.plugins import NodePlugin
from meshroom.core.exception import GraphCompatibilityError, NodeUpgradeError from meshroom.core.exception import GraphCompatibilityError, NodeUpgradeError
from meshroom.core.graph import Graph, loadGraph from meshroom.core.graph import Graph, loadGraph
from meshroom.core.node import CompatibilityNode, CompatibilityIssue, Node from meshroom.core.node import CompatibilityNode, CompatibilityIssue, Node
@ -170,21 +170,22 @@ class SampleInputNodeV2(desc.InputNode):
def replaceNodeTypeDesc(nodeType: str, nodeDesc: Type[desc.Node]): def replaceNodeTypeDesc(nodeType: str, nodeDesc: Type[desc.Node]):
"""Change the `nodeDesc` associated to `nodeType`.""" """Change the `nodeDesc` associated to `nodeType`."""
meshroom.core.nodesDesc[nodeType] = nodeDesc pluginManager.getNodePlugins()[nodeType] = NodePlugin(nodeDesc)
def test_unknown_node_type(): def test_unknown_node_type():
""" """
Test compatibility behavior for unknown node type. Test compatibility behavior for unknown node type.
""" """
registerNodeType(SampleNodeV1) nodePlugin = NodePlugin(SampleNodeV1)
pluginManager.registerNode(nodePlugin)
g = Graph("") g = Graph("")
n = g.addNewNode("SampleNodeV1", input="/dev/null", paramA="foo") n = g.addNewNode("SampleNodeV1", input="/dev/null", paramA="foo")
graphFile = os.path.join(tempfile.mkdtemp(), "test_unknown_node_type.mg") graphFile = os.path.join(tempfile.mkdtemp(), "test_unknown_node_type.mg")
g.save(graphFile) g.save(graphFile)
internalFolder = n.internalFolder internalFolder = n.internalFolder
nodeName = n.name nodeName = n.name
unregisterNodeType(SampleNodeV1) pluginManager.unregisterNode(nodePlugin)
# Reload file # Reload file
@ -328,14 +329,18 @@ def test_description_conflict():
raise ValueError("Unexpected node type: " + srcNode.nodeType) raise ValueError("Unexpected node type: " + srcNode.nodeType)
# Restore original node types # Restore original node types
meshroom.core.nodesDesc = originalNodeTypes pluginManager._nodePlugins = originalNodeTypes
def test_upgradeAllNodes(): def test_upgradeAllNodes():
registerNodeType(SampleNodeV1) nodePluginSampleV1 = NodePlugin(SampleNodeV1)
registerNodeType(SampleNodeV2) nodePluginSampleV2 = NodePlugin(SampleNodeV2)
registerNodeType(SampleInputNodeV1) nodePluginSampleInputV1 = NodePlugin(SampleInputNodeV1)
registerNodeType(SampleInputNodeV2) nodePluginSampleInputV2 = NodePlugin(SampleInputNodeV2)
pluginManager.registerNode(nodePluginSampleV1)
pluginManager.registerNode(nodePluginSampleV2)
pluginManager.registerNode(nodePluginSampleInputV1)
pluginManager.registerNode(nodePluginSampleInputV2)
g = Graph("") g = Graph("")
n1 = g.addNewNode("SampleNodeV1") n1 = g.addNewNode("SampleNodeV1")
@ -350,11 +355,13 @@ def test_upgradeAllNodes():
g.save(graphFile) g.save(graphFile)
# Make SampleNodeV2 and SampleInputNodeV2 an unknown type # Make SampleNodeV2 and SampleInputNodeV2 an unknown type
unregisterNodeType(SampleNodeV2) pluginManager.unregisterNode(nodePluginSampleV2)
unregisterNodeType(SampleInputNodeV2) pluginManager.unregisterNode(nodePluginSampleInputV2)
meshroom.core.nodesDesc[SampleNodeV1.__name__] = SampleNodeV2
meshroom.core.nodesDesc[SampleInputNodeV1.__name__] = SampleInputNodeV2
# Replace SampleNodeV1 by SampleNodeV2 and SampleInputNodeV1 by SampleInputNodeV2 # Replace SampleNodeV1 by SampleNodeV2 and SampleInputNodeV1 by SampleInputNodeV2
pluginManager.getNodePlugins()[nodePluginSampleV1.nodeDescriptor.__name__] = nodePluginSampleV2
pluginManager.getNodePlugins()[nodePluginSampleInputV1.nodeDescriptor.__name__] = \
nodePluginSampleInputV2
# Reload file # Reload file
g = loadGraph(graphFile) g = loadGraph(graphFile)
@ -375,13 +382,15 @@ def test_upgradeAllNodes():
assert n2Name in g.compatibilityNodes.keys() assert n2Name in g.compatibilityNodes.keys()
assert n4Name in g.compatibilityNodes.keys() assert n4Name in g.compatibilityNodes.keys()
unregisterNodeType(SampleNodeV1) pluginManager.unregisterNode(nodePluginSampleV1)
unregisterNodeType(SampleInputNodeV1) pluginManager.unregisterNode(nodePluginSampleInputV1)
def test_conformUpgrade(): def test_conformUpgrade():
registerNodeType(SampleNodeV5) nodePluginSampleV5 = NodePlugin(SampleNodeV5)
registerNodeType(SampleNodeV6) nodePluginSampleV6 = NodePlugin(SampleNodeV6)
pluginManager.registerNode(nodePluginSampleV5)
pluginManager.registerNode(nodePluginSampleV6)
g = Graph("") g = Graph("")
n1 = g.addNewNode("SampleNodeV5") n1 = g.addNewNode("SampleNodeV5")
@ -391,7 +400,7 @@ def test_conformUpgrade():
g.save(graphFile) g.save(graphFile)
# Replace SampleNodeV5 by SampleNodeV6 # Replace SampleNodeV5 by SampleNodeV6
meshroom.core.nodesDesc[SampleNodeV5.__name__] = SampleNodeV6 pluginManager.getNodePlugins()[nodePluginSampleV5.nodeDescriptor.__name__] = nodePluginSampleV6
# Reload file # Reload file
g = loadGraph(graphFile) g = loadGraph(graphFile)
@ -415,8 +424,8 @@ def test_conformUpgrade():
# Check conformation # Check conformation
assert len(upgradedNode.paramA.value) == 1 assert len(upgradedNode.paramA.value) == 1
unregisterNodeType(SampleNodeV5) pluginManager.unregisterNode(nodePluginSampleV5)
unregisterNodeType(SampleNodeV6) pluginManager.unregisterNode(nodePluginSampleV6)
class TestGraphLoadingWithStrictCompatibility: class TestGraphLoadingWithStrictCompatibility:

View file

@ -1,7 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# coding:utf-8 # coding:utf-8
from meshroom.core.graph import Graph from meshroom.core.graph import Graph
from meshroom.core import desc, registerNodeType from meshroom.core import desc, pluginManager
from meshroom.core.plugins import NodePlugin
class SampleNode(desc.Node): class SampleNode(desc.Node):
@ -16,9 +17,8 @@ class SampleNode(desc.Node):
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}") desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
] ]
nodePlugin = NodePlugin(SampleNode)
registerNodeType(SampleNode) pluginManager.registerNode(nodePlugin) # register standalone NodePlugin
def test_output_invalidation(): def test_output_invalidation():
graph = Graph("") graph = Graph("")

View file

@ -1,8 +1,9 @@
# coding:utf-8 # coding:utf-8
from meshroom.core.graph import Graph, loadGraph, executeGraph from meshroom.core.graph import Graph, loadGraph, executeGraph
from meshroom.core import desc, registerNodeType, unregisterNodeType from meshroom.core import desc, pluginManager
from meshroom.core.node import Node from meshroom.core.node import Node
from meshroom.core.plugins import NodePlugin
class NodeWithAttributeChangedCallback(desc.BaseNode): class NodeWithAttributeChangedCallback(desc.BaseNode):
@ -37,13 +38,15 @@ class NodeWithAttributeChangedCallback(desc.BaseNode):
class TestNodeWithAttributeChangedCallback: class TestNodeWithAttributeChangedCallback:
nodePlugin = NodePlugin(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithAttributeChangedCallback) pluginManager.registerNode(cls.nodePlugin)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithAttributeChangedCallback) pluginManager.unregisterNode(cls.nodePlugin)
def test_assignValueTriggersCallback(self): def test_assignValueTriggersCallback(self):
node = Node(NodeWithAttributeChangedCallback.__name__) node = Node(NodeWithAttributeChangedCallback.__name__)
@ -68,13 +71,15 @@ class TestNodeWithAttributeChangedCallback:
class TestAttributeCallbackTriggerInGraph: class TestAttributeCallbackTriggerInGraph:
nodePlugin = NodePlugin(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithAttributeChangedCallback) pluginManager.registerNode(cls.nodePlugin)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithAttributeChangedCallback) pluginManager.unregisterNode(cls.nodePlugin)
def test_connectionTriggersCallback(self): def test_connectionTriggersCallback(self):
graph = Graph("") graph = Graph("")
@ -219,7 +224,7 @@ class NodeWithCompoundAttributes(desc.BaseNode):
desc.IntParam( desc.IntParam(
name="int", label="Int", description="", value=0, range=None name="int", label="Int", description="", value=0, range=None
) )
], ],
) )
), ),
desc.GroupAttribute( desc.GroupAttribute(
@ -241,15 +246,18 @@ class NodeWithCompoundAttributes(desc.BaseNode):
class TestAttributeCallbackBehaviorWithUpstreamCompoundAttributes: class TestAttributeCallbackBehaviorWithUpstreamCompoundAttributes:
nodePluginAttributeChangedCallback = NodePlugin(NodeWithAttributeChangedCallback)
nodePluginCompoundAttributes = NodePlugin(NodeWithCompoundAttributes)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithAttributeChangedCallback) pluginManager.registerNode(cls.nodePluginAttributeChangedCallback)
registerNodeType(NodeWithCompoundAttributes) pluginManager.registerNode(cls.nodePluginCompoundAttributes)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithAttributeChangedCallback) pluginManager.unregisterNode(cls.nodePluginAttributeChangedCallback)
unregisterNodeType(NodeWithCompoundAttributes) pluginManager.unregisterNode(cls.nodePluginCompoundAttributes)
def test_connectionToListElement(self): def test_connectionToListElement(self):
graph = Graph("") graph = Graph("")
@ -341,15 +349,18 @@ class NodeWithDynamicOutputValue(desc.BaseNode):
class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs: class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
nodePluginAttributeChangedCallback = NodePlugin(NodeWithAttributeChangedCallback)
nodePluginDynamicOutputValue = NodePlugin(NodeWithDynamicOutputValue)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithAttributeChangedCallback) pluginManager.registerNode(cls.nodePluginAttributeChangedCallback)
registerNodeType(NodeWithDynamicOutputValue) pluginManager.registerNode(cls.nodePluginDynamicOutputValue)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithAttributeChangedCallback) pluginManager.unregisterNode(cls.nodePluginAttributeChangedCallback)
unregisterNodeType(NodeWithDynamicOutputValue) pluginManager.unregisterNode(cls.nodePluginDynamicOutputValue)
def test_connectingUncomputedDynamicOutputDoesNotTriggerDownstreamAttributeChangedCallback( def test_connectingUncomputedDynamicOutputDoesNotTriggerDownstreamAttributeChangedCallback(
self, self,
@ -432,13 +443,15 @@ class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
class TestAttributeCallbackBehaviorOnGraphImport: class TestAttributeCallbackBehaviorOnGraphImport:
nodePlugin = NodePlugin(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithAttributeChangedCallback) pluginManager.registerNode(cls.nodePlugin)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithAttributeChangedCallback) pluginManager.unregisterNode(cls.nodePlugin)
def test_importingGraphDoesNotTriggerAttributeChangedCallbacks(self): def test_importingGraphDoesNotTriggerAttributeChangedCallbacks(self):
graph = Graph("") graph = Graph("")

View file

@ -1,6 +1,7 @@
from meshroom.core import desc, registerNodeType, unregisterNodeType from meshroom.core import desc, pluginManager
from meshroom.core.node import Node from meshroom.core.node import Node
from meshroom.core.graph import Graph, loadGraph from meshroom.core.graph import Graph, loadGraph
from meshroom.core.plugins import NodePlugin
class NodeWithCreationCallback(desc.InputNode): class NodeWithCreationCallback(desc.InputNode):
@ -22,13 +23,15 @@ class NodeWithCreationCallback(desc.InputNode):
class TestNodeCreationCallback: class TestNodeCreationCallback:
nodePlugin = NodePlugin(NodeWithCreationCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithCreationCallback) pluginManager.registerNode(cls.nodePlugin)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithCreationCallback) pluginManager.unregisterNode(cls.nodePlugin)
def test_notTriggeredOnNodeInstantiation(self): def test_notTriggeredOnNodeInstantiation(self):
node = Node(NodeWithCreationCallback.__name__) node = Node(NodeWithCreationCallback.__name__)

View file

@ -2,8 +2,9 @@
# coding:utf-8 # coding:utf-8
from meshroom.core.graph import Graph, loadGraph, executeGraph from meshroom.core.graph import Graph, loadGraph, executeGraph
from meshroom.core import desc, registerNodeType, unregisterNodeType from meshroom.core import desc, pluginManager
from meshroom.core.node import Node from meshroom.core.node import Node
from meshroom.core.plugins import NodePlugin
class NodeWithAttributesNeedingFormatting(desc.Node): class NodeWithAttributesNeedingFormatting(desc.Node):
@ -100,13 +101,15 @@ class NodeWithAttributesNeedingFormatting(desc.Node):
] ]
class TestCommandLineFormatting: class TestCommandLineFormatting:
nodePlugin = NodePlugin(NodeWithAttributesNeedingFormatting)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
registerNodeType(NodeWithAttributesNeedingFormatting) pluginManager.registerNode(cls.nodePlugin)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
unregisterNodeType(NodeWithAttributesNeedingFormatting) pluginManager.unregisterNode(cls.nodePlugin)
def test_formatting_listOfFiles(self): def test_formatting_listOfFiles(self):
inputImages = ["/non/existing/fileA", "/non/existing/with space/fileB"] inputImages = ["/non/existing/fileA", "/non/existing/with space/fileB"]

View file

@ -1,23 +1,25 @@
from contextlib import contextmanager from contextlib import contextmanager
from unittest.mock import patch from unittest.mock import patch
from typing import Type
import meshroom import meshroom
from meshroom.core import registerNodeType, unregisterNodeType from meshroom.core import desc, pluginManager
from meshroom.core import desc from meshroom.core.plugins import NodePlugin
@contextmanager @contextmanager
def registeredNodeTypes(nodeTypes: list[Type[desc.Node]]): def registeredNodeTypes(nodeTypes: list[desc.Node]):
nodePluginsList = {}
for nodeType in nodeTypes: for nodeType in nodeTypes:
registerNodeType(nodeType) nodePlugin = NodePlugin(nodeType)
pluginManager.registerNode(nodePlugin)
nodePluginsList[nodeType] = nodePlugin
yield yield
for nodeType in nodeTypes: for nodeType in nodeTypes:
unregisterNodeType(nodeType) pluginManager.unregisterNode(nodePluginsList[nodeType])
@contextmanager @contextmanager
def overrideNodeTypeVersion(nodeType: Type[desc.Node], version: str): def overrideNodeTypeVersion(nodeType: desc.Node, version: str):
""" Helper context manager to override the version of a given node type. """ """ Helper context manager to override the version of a given node type. """
unpatchedFunc = meshroom.core.nodeVersion unpatchedFunc = meshroom.core.nodeVersion
with patch.object( with patch.object(