[tests] Simplify registration/unregistration of nodes in tests

Add two methods that are local to tests, `registerNodeDesc` and
`unregisterNodeDesc`, which handle the registration and unregistration
of `NodePlugins` from a node description. This reduces the amount of
code in tests whenever `NodePlugin` need to be instantiated prior
to their registration and so on.
This commit is contained in:
Candice Bentéjac 2025-06-04 21:18:16 +02:00
parent 424abbff82
commit 3c57afb4d0
8 changed files with 76 additions and 77 deletions

View file

@ -1,7 +1,7 @@
from meshroom.core import desc, pluginManager 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
from .utils import registerNodeDesc, unregisterNodeDesc
class NodeWithChoiceParams(desc.Node): class NodeWithChoiceParams(desc.Node):
inputs = [ inputs = [
@ -53,15 +53,14 @@ class NodeWithChoiceParamsSavingValuesOverride(desc.Node):
class TestChoiceParam: class TestChoiceParam:
nodePlugin = NodePlugin(NodeWithChoiceParams)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePlugin) registerNodeDesc(NodeWithChoiceParams)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePlugin) unregisterNodeDesc(NodeWithChoiceParams)
def test_customValueIsSerialized(self, graphSavedOnDisk): def test_customValueIsSerialized(self, graphSavedOnDisk):
graph: Graph = graphSavedOnDisk graph: Graph = graphSavedOnDisk
@ -120,15 +119,14 @@ class TestChoiceParam:
class TestChoiceParamSavingCustomValues: class TestChoiceParamSavingCustomValues:
nodePlugin = NodePlugin(NodeWithChoiceParamsSavingValuesOverride)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePlugin) registerNodeDesc(NodeWithChoiceParamsSavingValuesOverride)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePlugin) unregisterNodeDesc(NodeWithChoiceParamsSavingValuesOverride)
def test_customValueIsSerialized(self, graphSavedOnDisk): def test_customValueIsSerialized(self, graphSavedOnDisk):
graph: Graph = graphSavedOnDisk graph: Graph = graphSavedOnDisk

View file

@ -13,7 +13,7 @@ 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
from .utils import registeredNodeTypes, overrideNodeTypeVersion from .utils import registeredNodeTypes, overrideNodeTypeVersion, registerNodeDesc, unregisterNodeDesc
SampleGroupV1 = [ SampleGroupV1 = [
@ -177,15 +177,14 @@ def test_unknown_node_type():
""" """
Test compatibility behavior for unknown node type. Test compatibility behavior for unknown node type.
""" """
nodePlugin = NodePlugin(SampleNodeV1) registerNodeDesc(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
pluginManager.unregisterNode(nodePlugin) unregisterNodeDesc(SampleNodeV1)
# Reload file # Reload file
@ -224,7 +223,7 @@ def test_description_conflict():
# Register and instantiate instances of all node types except last one # Register and instantiate instances of all node types except last one
for nt in nodeTypes[:-1]: for nt in nodeTypes[:-1]:
pluginManager.registerNode(NodePlugin(nt)) registerNodeDesc(nt)
n = g.addNewNode(nt.__name__) n = g.addNewNode(nt.__name__)
if nt == SampleNodeV4: if nt == SampleNodeV4:
@ -332,15 +331,10 @@ def test_description_conflict():
pluginManager._nodePlugins = originalNodeTypes pluginManager._nodePlugins = originalNodeTypes
def test_upgradeAllNodes(): def test_upgradeAllNodes():
nodePluginSampleV1 = NodePlugin(SampleNodeV1) registerNodeDesc(SampleNodeV1)
nodePluginSampleV2 = NodePlugin(SampleNodeV2) registerNodeDesc(SampleNodeV2)
nodePluginSampleInputV1 = NodePlugin(SampleInputNodeV1) registerNodeDesc(SampleInputNodeV1)
nodePluginSampleInputV2 = NodePlugin(SampleInputNodeV2) registerNodeDesc(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")
@ -354,14 +348,15 @@ def test_upgradeAllNodes():
graphFile = os.path.join(tempfile.mkdtemp(), "test_description_conflict.mg") graphFile = os.path.join(tempfile.mkdtemp(), "test_description_conflict.mg")
g.save(graphFile) g.save(graphFile)
# Make SampleNodeV2 and SampleInputNodeV2 an unknown type
pluginManager.unregisterNode(nodePluginSampleV2)
pluginManager.unregisterNode(nodePluginSampleInputV2)
# Replace SampleNodeV1 by SampleNodeV2 and SampleInputNodeV1 by SampleInputNodeV2 # Replace SampleNodeV1 by SampleNodeV2 and SampleInputNodeV1 by SampleInputNodeV2
pluginManager.getRegisteredNodePlugins()[nodePluginSampleV1.nodeDescriptor.__name__] = nodePluginSampleV2 pluginManager.getRegisteredNodePlugins()[SampleNodeV1.__name__] = \
pluginManager.getRegisteredNodePlugins()[nodePluginSampleInputV1.nodeDescriptor.__name__] = \ pluginManager.getRegisteredNodePlugin(SampleNodeV2.__name__)
nodePluginSampleInputV2 pluginManager.getRegisteredNodePlugins()[SampleInputNodeV1.__name__] = \
pluginManager.getRegisteredNodePlugin(SampleInputNodeV2.__name__)
# Make SampleNodeV2 and SampleInputNodeV2 an unknown type
unregisterNodeDesc(SampleNodeV2)
unregisterNodeDesc(SampleInputNodeV2)
# Reload file # Reload file
g = loadGraph(graphFile) g = loadGraph(graphFile)
@ -382,15 +377,13 @@ 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()
pluginManager.unregisterNode(nodePluginSampleV1) unregisterNodeDesc(SampleNodeV1)
pluginManager.unregisterNode(nodePluginSampleInputV1) unregisterNodeDesc(SampleInputNodeV1)
def test_conformUpgrade(): def test_conformUpgrade():
nodePluginSampleV5 = NodePlugin(SampleNodeV5) registerNodeDesc(SampleNodeV5)
nodePluginSampleV6 = NodePlugin(SampleNodeV6) registerNodeDesc(SampleNodeV6)
pluginManager.registerNode(nodePluginSampleV5)
pluginManager.registerNode(nodePluginSampleV6)
g = Graph("") g = Graph("")
n1 = g.addNewNode("SampleNodeV5") n1 = g.addNewNode("SampleNodeV5")
@ -400,7 +393,8 @@ def test_conformUpgrade():
g.save(graphFile) g.save(graphFile)
# Replace SampleNodeV5 by SampleNodeV6 # Replace SampleNodeV5 by SampleNodeV6
pluginManager.getRegisteredNodePlugins()[nodePluginSampleV5.nodeDescriptor.__name__] = nodePluginSampleV6 pluginManager.getRegisteredNodePlugins()[SampleNodeV5.__name__] = \
pluginManager.getRegisteredNodePlugin(SampleNodeV6.__name__)
# Reload file # Reload file
g = loadGraph(graphFile) g = loadGraph(graphFile)
@ -424,8 +418,8 @@ def test_conformUpgrade():
# Check conformation # Check conformation
assert len(upgradedNode.paramA.value) == 1 assert len(upgradedNode.paramA.value) == 1
pluginManager.unregisterNode(nodePluginSampleV5) unregisterNodeDesc(SampleNodeV5)
pluginManager.unregisterNode(nodePluginSampleV6) unregisterNodeDesc(SampleNodeV6)
class TestGraphLoadingWithStrictCompatibility: class TestGraphLoadingWithStrictCompatibility:
@ -441,7 +435,6 @@ class TestGraphLoadingWithStrictCompatibility:
def test_failsOnNodeDescriptionCompatibilityIssue(self, graphSavedOnDisk): def test_failsOnNodeDescriptionCompatibilityIssue(self, graphSavedOnDisk):
with registeredNodeTypes([SampleNodeV1, SampleNodeV2]): with registeredNodeTypes([SampleNodeV1, SampleNodeV2]):
graph: Graph = graphSavedOnDisk graph: Graph = graphSavedOnDisk
graph.addNewNode(SampleNodeV1.__name__) graph.addNewNode(SampleNodeV1.__name__)
@ -456,7 +449,6 @@ class TestGraphLoadingWithStrictCompatibility:
class TestGraphTemplateLoading: class TestGraphTemplateLoading:
def test_failsOnUnknownNodeTypeError(self, graphSavedOnDisk): def test_failsOnUnknownNodeTypeError(self, graphSavedOnDisk):
with registeredNodeTypes([SampleNodeV1, SampleNodeV2]): with registeredNodeTypes([SampleNodeV1, SampleNodeV2]):
graph: Graph = graphSavedOnDisk graph: Graph = graphSavedOnDisk
graph.addNewNode(SampleNodeV1.__name__) graph.addNewNode(SampleNodeV1.__name__)

View file

@ -2,7 +2,8 @@
# coding:utf-8 # coding:utf-8
from meshroom.core.graph import Graph from meshroom.core.graph import Graph
from meshroom.core import desc, pluginManager from meshroom.core import desc, pluginManager
from meshroom.core.plugins import NodePlugin
from .utils import registerNodeDesc
class SampleNode(desc.Node): class SampleNode(desc.Node):
@ -17,8 +18,7 @@ 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) registerNodeDesc(SampleNode) # register standalone NodePlugin
pluginManager.registerNode(nodePlugin) # register standalone NodePlugin
def test_output_invalidation(): def test_output_invalidation():
graph = Graph("") graph = Graph("")

View file

@ -3,7 +3,8 @@
from meshroom.core.graph import Graph, loadGraph, executeGraph from meshroom.core.graph import Graph, loadGraph, executeGraph
from meshroom.core import desc, pluginManager from meshroom.core import desc, pluginManager
from meshroom.core.node import Node from meshroom.core.node import Node
from meshroom.core.plugins import NodePlugin
from .utils import registerNodeDesc, unregisterNodeDesc
class NodeWithAttributeChangedCallback(desc.BaseNode): class NodeWithAttributeChangedCallback(desc.BaseNode):
@ -38,15 +39,14 @@ class NodeWithAttributeChangedCallback(desc.BaseNode):
class TestNodeWithAttributeChangedCallback: class TestNodeWithAttributeChangedCallback:
nodePlugin = NodePlugin(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePlugin) registerNodeDesc(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePlugin) unregisterNodeDesc(NodeWithAttributeChangedCallback)
def test_assignValueTriggersCallback(self): def test_assignValueTriggersCallback(self):
node = Node(NodeWithAttributeChangedCallback.__name__) node = Node(NodeWithAttributeChangedCallback.__name__)
@ -71,15 +71,14 @@ class TestNodeWithAttributeChangedCallback:
class TestAttributeCallbackTriggerInGraph: class TestAttributeCallbackTriggerInGraph:
nodePlugin = NodePlugin(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePlugin) registerNodeDesc(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePlugin) unregisterNodeDesc(NodeWithAttributeChangedCallback)
def test_connectionTriggersCallback(self): def test_connectionTriggersCallback(self):
graph = Graph("") graph = Graph("")
@ -246,18 +245,16 @@ class NodeWithCompoundAttributes(desc.BaseNode):
class TestAttributeCallbackBehaviorWithUpstreamCompoundAttributes: class TestAttributeCallbackBehaviorWithUpstreamCompoundAttributes:
nodePluginAttributeChangedCallback = NodePlugin(NodeWithAttributeChangedCallback)
nodePluginCompoundAttributes = NodePlugin(NodeWithCompoundAttributes)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePluginAttributeChangedCallback) registerNodeDesc(NodeWithAttributeChangedCallback)
pluginManager.registerNode(cls.nodePluginCompoundAttributes) registerNodeDesc(NodeWithCompoundAttributes)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePluginAttributeChangedCallback) unregisterNodeDesc(NodeWithAttributeChangedCallback)
pluginManager.unregisterNode(cls.nodePluginCompoundAttributes) unregisterNodeDesc(NodeWithCompoundAttributes)
def test_connectionToListElement(self): def test_connectionToListElement(self):
graph = Graph("") graph = Graph("")
@ -349,18 +346,18 @@ class NodeWithDynamicOutputValue(desc.BaseNode):
class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs: class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
nodePluginAttributeChangedCallback = NodePlugin(NodeWithAttributeChangedCallback) # nodePluginAttributeChangedCallback = NodePlugin(NodeWithAttributeChangedCallback)
nodePluginDynamicOutputValue = NodePlugin(NodeWithDynamicOutputValue) # nodePluginDynamicOutputValue = NodePlugin(NodeWithDynamicOutputValue)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePluginAttributeChangedCallback) registerNodeDesc(NodeWithAttributeChangedCallback)
pluginManager.registerNode(cls.nodePluginDynamicOutputValue) registerNodeDesc(NodeWithDynamicOutputValue)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePluginAttributeChangedCallback) unregisterNodeDesc(NodeWithAttributeChangedCallback)
pluginManager.unregisterNode(cls.nodePluginDynamicOutputValue) unregisterNodeDesc(NodeWithDynamicOutputValue)
def test_connectingUncomputedDynamicOutputDoesNotTriggerDownstreamAttributeChangedCallback( def test_connectingUncomputedDynamicOutputDoesNotTriggerDownstreamAttributeChangedCallback(
self, self,
@ -443,15 +440,13 @@ class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
class TestAttributeCallbackBehaviorOnGraphImport: class TestAttributeCallbackBehaviorOnGraphImport:
nodePlugin = NodePlugin(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePlugin) registerNodeDesc(NodeWithAttributeChangedCallback)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePlugin) unregisterNodeDesc(NodeWithAttributeChangedCallback)
def test_importingGraphDoesNotTriggerAttributeChangedCallbacks(self): def test_importingGraphDoesNotTriggerAttributeChangedCallbacks(self):
graph = Graph("") graph = Graph("")

View file

@ -1,7 +1,8 @@
from meshroom.core import desc, pluginManager 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
from .utils import registerNodeDesc, unregisterNodeDesc
class NodeWithCreationCallback(desc.InputNode): class NodeWithCreationCallback(desc.InputNode):
@ -23,15 +24,14 @@ class NodeWithCreationCallback(desc.InputNode):
class TestNodeCreationCallback: class TestNodeCreationCallback:
nodePlugin = NodePlugin(NodeWithCreationCallback)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePlugin) registerNodeDesc(NodeWithCreationCallback)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePlugin) unregisterNodeDesc(NodeWithCreationCallback)
def test_notTriggeredOnNodeInstantiation(self): def test_notTriggeredOnNodeInstantiation(self):
node = Node(NodeWithCreationCallback.__name__) node = Node(NodeWithCreationCallback.__name__)

View file

@ -4,7 +4,8 @@
from meshroom.core.graph import Graph, loadGraph, executeGraph from meshroom.core.graph import Graph, loadGraph, executeGraph
from meshroom.core import desc, pluginManager from meshroom.core import desc, pluginManager
from meshroom.core.node import Node from meshroom.core.node import Node
from meshroom.core.plugins import NodePlugin
from .utils import registerNodeDesc, unregisterNodeDesc
class NodeWithAttributesNeedingFormatting(desc.Node): class NodeWithAttributesNeedingFormatting(desc.Node):
@ -101,15 +102,14 @@ class NodeWithAttributesNeedingFormatting(desc.Node):
] ]
class TestCommandLineFormatting: class TestCommandLineFormatting:
nodePlugin = NodePlugin(NodeWithAttributesNeedingFormatting)
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
pluginManager.registerNode(cls.nodePlugin) registerNodeDesc(NodeWithAttributesNeedingFormatting)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterNode(cls.nodePlugin) unregisterNodeDesc(NodeWithAttributesNeedingFormatting)
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

@ -3,7 +3,6 @@
from meshroom.core import desc, pluginManager, loadClassesNodes from meshroom.core import desc, pluginManager, loadClassesNodes
from meshroom.core.plugins import NodePluginStatus, Plugin from meshroom.core.plugins import NodePluginStatus, Plugin
from itertools import islice
import os import os
class TestPluginWithValidNodesOnly: class TestPluginWithValidNodesOnly:
@ -21,7 +20,8 @@ class TestPluginWithValidNodesOnly:
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterPlugin(cls.plugin) for node in cls.plugin.nodes.values():
pluginManager.unregisterNode(node)
cls.plugin = None cls.plugin = None
def test_loadedPlugin(self): def test_loadedPlugin(self):
@ -127,7 +127,8 @@ class TestPluginWithInvalidNodes:
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
pluginManager.unregisterPlugin(cls.plugin) for node in cls.plugin.nodes.values():
pluginManager.unregisterNode(node)
cls.plugin = None cls.plugin = None
def test_loadedPlugin(self): def test_loadedPlugin(self):

View file

@ -3,7 +3,7 @@ from unittest.mock import patch
import meshroom import meshroom
from meshroom.core import desc, pluginManager from meshroom.core import desc, pluginManager
from meshroom.core.plugins import NodePlugin from meshroom.core.plugins import NodePlugin, NodePluginStatus
@contextmanager @contextmanager
def registeredNodeTypes(nodeTypes: list[desc.Node]): def registeredNodeTypes(nodeTypes: list[desc.Node]):
@ -28,3 +28,16 @@ def overrideNodeTypeVersion(nodeType: desc.Node, version: str):
side_effect=lambda type: version if type is nodeType else unpatchedFunc(type), side_effect=lambda type: version if type is nodeType else unpatchedFunc(type),
): ):
yield yield
def registerNodeDesc(nodeDesc: desc.Node):
name = nodeDesc.__name__
if not pluginManager.isRegistered(name):
pluginManager._nodePlugins[name] = NodePlugin(nodeDesc)
pluginManager._nodePlugins[name].status = NodePluginStatus.LOADED
def unregisterNodeDesc(nodeDesc: desc.Node):
name = nodeDesc.__name__
if pluginManager.isRegistered(name):
plugin = pluginManager.getRegisteredNodePlugin(name)
plugin.status = NodePluginStatus.NOT_LOADED
del pluginManager._nodePlugins[name]