[tests] Harmonize and clean-up syntax across test files

Also comply more with PEP8 linting rules.
This commit is contained in:
Candice Bentéjac 2025-05-12 17:31:59 +02:00
parent 441ba37c24
commit 28042dd2ad
11 changed files with 218 additions and 189 deletions

View file

@ -39,4 +39,3 @@ class AppendFiles(desc.CommandLineNode):
value='{nodeCacheFolder}/appendText.txt',
)
]

View file

@ -2,21 +2,21 @@ from meshroom.core import desc
class Ls(desc.CommandLineNode):
commandLine = 'ls {inputValue} > {outputValue}'
commandLine = "ls {inputValue} > {outputValue}"
inputs = [
desc.File(
name='input',
label='Input',
description='''''',
value='',
name="input",
label="Input",
description="",
value="",
)
]
outputs = [
desc.File(
name='output',
label='Output',
description='''''',
value='{nodeCacheFolder}/ls.txt',
name="output",
label="Output",
description="",
value="{nodeCacheFolder}/ls.txt",
)
]

View file

@ -20,7 +20,8 @@ SampleGroupV1 = [
desc.IntParam(name="a", label="a", description="", value=0, range=None),
desc.ListAttribute(
name="b",
elementDesc=desc.FloatParam(name="p", label="", description="", value=0.0, range=None),
elementDesc=desc.FloatParam(name="p", label="",
description="", value=0.0, range=None),
label="b",
description="",
)
@ -30,7 +31,8 @@ SampleGroupV2 = [
desc.IntParam(name="a", label="a", description="", value=0, range=None),
desc.ListAttribute(
name="b",
elementDesc=desc.GroupAttribute(name="p", label="", description="", groupDesc=SampleGroupV1),
elementDesc=desc.GroupAttribute(name="p", label="",
description="", groupDesc=SampleGroupV1),
label="b",
description="",
)
@ -39,10 +41,12 @@ SampleGroupV2 = [
# SampleGroupV3 is SampleGroupV2 with one more int parameter
SampleGroupV3 = [
desc.IntParam(name="a", label="a", description="", value=0, range=None),
desc.IntParam(name="notInSampleGroupV2", label="notInSampleGroupV2", description="", value=0, range=None),
desc.IntParam(name="notInSampleGroupV2", label="notInSampleGroupV2",
description="", value=0, range=None),
desc.ListAttribute(
name="b",
elementDesc=desc.GroupAttribute(name="p", label="", description="", groupDesc=SampleGroupV1),
elementDesc=desc.GroupAttribute(name="p", label="",
description="", groupDesc=SampleGroupV1),
label="b",
description="",
)
@ -52,11 +56,12 @@ SampleGroupV3 = [
class SampleNodeV1(desc.Node):
""" Version 1 Sample Node """
inputs = [
desc.File(name='input', label='Input', description='', value='',),
desc.StringParam(name='paramA', label='ParamA', description='', value='', invalidate=False) # No impact on UID
desc.File(name="input", label="Input", description="", value=""),
desc.StringParam(name="paramA", label="ParamA", description="",
value="", invalidate=False) # No impact on UID
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
@ -65,11 +70,12 @@ class SampleNodeV2(desc.Node):
* 'input' has been renamed to 'in'
"""
inputs = [
desc.File(name='in', label='Input', description='', value='',),
desc.StringParam(name='paramA', label='ParamA', description='', value='', invalidate=False), # No impact on UID
desc.File(name="in", label="Input", description="", value=""),
desc.StringParam(name="paramA", label="ParamA", description="",
value="", invalidate=False), # No impact on UID
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
@ -79,10 +85,10 @@ class SampleNodeV3(desc.Node):
* 'paramA' has been removed'
"""
inputs = [
desc.File(name='in', label='Input', description='', value='',),
desc.File(name="in", label="Input", description="", value=""),
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
@ -92,14 +98,14 @@ class SampleNodeV4(desc.Node):
* 'paramA' has been added
"""
inputs = [
desc.File(name='in', label='Input', description='', value='',),
desc.ListAttribute(name='paramA', label='ParamA',
desc.File(name="in", label="Input", description="", value=""),
desc.ListAttribute(name="paramA", label="ParamA",
elementDesc=desc.GroupAttribute(
groupDesc=SampleGroupV1, name='gA', label='gA', description=''),
description='')
groupDesc=SampleGroupV1, name="gA", label="gA", description=""),
description="")
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
@ -109,14 +115,14 @@ class SampleNodeV5(desc.Node):
* 'paramA' elementDesc has changed from SampleGroupV1 to SampleGroupV2
"""
inputs = [
desc.File(name='in', label='Input', description='', value=''),
desc.ListAttribute(name='paramA', label='ParamA',
desc.File(name="in", label="Input", description="", value=""),
desc.ListAttribute(name="paramA", label="ParamA",
elementDesc=desc.GroupAttribute(
groupDesc=SampleGroupV2, name='gA', label='gA', description=''),
description='')
groupDesc=SampleGroupV2, name="gA", label="gA", description=""),
description="")
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
@ -126,24 +132,25 @@ class SampleNodeV6(desc.Node):
* 'paramA' elementDesc has changed from SampleGroupV2 to SampleGroupV3
"""
inputs = [
desc.File(name='in', label='Input', description='', value=''),
desc.ListAttribute(name='paramA', label='ParamA',
desc.File(name="in", label="Input", description="", value=""),
desc.ListAttribute(name="paramA", label="ParamA",
elementDesc=desc.GroupAttribute(
groupDesc=SampleGroupV3, name='gA', label='gA', description=''),
description='')
groupDesc=SampleGroupV3, name="gA", label="gA", description=""),
description="")
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
class SampleInputNodeV1(desc.InputNode):
""" Version 1 Sample Input Node """
inputs = [
desc.StringParam(name='path', label='path', description='', value='', invalidate=False) # No impact on UID
desc.StringParam(name="path", label="Path", description="",
value="", invalidate=False) # No impact on UID
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
@ -152,10 +159,11 @@ class SampleInputNodeV2(desc.InputNode):
* 'path' has been renamed to 'in'
"""
inputs = [
desc.StringParam(name='in', label='path', description='', value='', invalidate=False) # No impact on UID
desc.StringParam(name="in", label="path", description="",
value="", invalidate=False) # No impact on UID
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")
]
@ -170,7 +178,7 @@ def test_unknown_node_type():
Test compatibility behavior for unknown node type.
"""
registerNodeType(SampleNodeV1)
g = Graph('')
g = Graph("")
n = g.addNewNode("SampleNodeV1", input="/dev/null", paramA="foo")
graphFile = os.path.join(tempfile.mkdtemp(), "test_unknown_node_type.mg")
g.save(graphFile)
@ -178,24 +186,25 @@ def test_unknown_node_type():
nodeName = n.name
unregisterNodeType(SampleNodeV1)
# reload file
# Reload file
g = loadGraph(graphFile)
os.remove(graphFile)
assert len(g.nodes) == 1
n = g.node(nodeName)
# SampleNodeV1 is now an unknown type
# check node instance type and compatibility issue type
# Check node instance type and compatibility issue type
assert isinstance(n, CompatibilityNode)
assert n.issue == CompatibilityIssue.UnknownNodeType
# check if attributes are properly restored
# Check if attributes are properly restored
assert len(n.attributes) == 3
assert n.input.isInput
assert n.output.isOutput
# check if internal folder
# Check if internal folder
assert n.internalFolder == internalFolder
# upgrade can't be perform on unknown node types
# Upgrade can't be perform on unknown node types
assert not n.canUpgrade
with pytest.raises(NodeUpgradeError):
g.upgradeNode(nodeName)
@ -205,20 +214,20 @@ def test_description_conflict():
"""
Test compatibility behavior for conflicting node descriptions.
"""
# copy registered node types to be able to restore them
originalNodeTypes = copy.copy(meshroom.core.nodesDesc)
# Copy registered node types to be able to restore them
originalNodeTypes = copy.deepcopy(pluginManager.getNodePlugins())
nodeTypes = [SampleNodeV1, SampleNodeV2, SampleNodeV3, SampleNodeV4, SampleNodeV5]
nodes = []
g = Graph('')
g = Graph("")
# 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]:
registerNodeType(nt)
pluginManager.registerNode(NodePlugin(nt))
n = g.addNewNode(nt.__name__)
if nt == SampleNodeV4:
# initialize list attribute with values to create a conflict with V5
# Initialize list attribute with values to create a conflict with V5
n.paramA.value = [{'a': 0, 'b': [1.0, 2.0]}]
nodes.append(n)
@ -226,15 +235,15 @@ def test_description_conflict():
graphFile = os.path.join(tempfile.mkdtemp(), "test_description_conflict.mg")
g.save(graphFile)
# reload file as-is, ensure no compatibility issue is detected (no CompatibilityNode instances)
# Reload file as-is, ensure no compatibility issue is detected (no CompatibilityNode instances)
loadGraph(graphFile, strictCompatibility=True)
# offset node types register to create description conflicts
# each node type name now reference the next one's implementation
# Offset node types register to create description conflicts
# Each node type name now reference the next one's implementation
for i, nt in enumerate(nodeTypes[:-1]):
meshroom.core.nodesDesc[nt.__name__] = nodeTypes[i+1]
pluginManager.getNodePlugins()[nt.__name__] = NodePlugin(nodeTypes[i + 1])
# reload file
# Reload file
g = loadGraph(graphFile)
os.remove(graphFile)
@ -246,7 +255,7 @@ def test_description_conflict():
assert isinstance(compatNode, CompatibilityNode)
assert srcNode.internalFolder == compatNode.internalFolder
# case by case description conflict verification
# Case by case description conflict verification
if isinstance(srcNode.nodeDesc, SampleNodeV1):
# V1 => V2: 'input' has been renamed to 'in'
assert len(compatNode.attributes) == 3
@ -254,27 +263,29 @@ def test_description_conflict():
assert hasattr(compatNode, "input")
assert not hasattr(compatNode, "in")
# perform upgrade
# Perform upgrade
upgradedNode = g.upgradeNode(nodeName)
assert isinstance(upgradedNode, Node) and isinstance(upgradedNode.nodeDesc, SampleNodeV2)
assert isinstance(upgradedNode, Node) and \
isinstance(upgradedNode.nodeDesc, SampleNodeV2)
assert list(upgradedNode.attributes.keys()) == ["in", "paramA", "output"]
assert not hasattr(upgradedNode, "input")
assert hasattr(upgradedNode, "in")
# check uid has changed (not the same set of attributes)
# Check UID has changed (not the same set of attributes)
assert upgradedNode.internalFolder != srcNode.internalFolder
elif isinstance(srcNode.nodeDesc, SampleNodeV2):
# V2 => V3: 'paramA' has been removed'
# V2 => V3: 'paramA' has been removed
assert len(compatNode.attributes) == 3
assert hasattr(compatNode, "paramA")
# perform upgrade
# Perform upgrade
upgradedNode = g.upgradeNode(nodeName)
assert isinstance(upgradedNode, Node) and isinstance(upgradedNode.nodeDesc, SampleNodeV3)
assert isinstance(upgradedNode, Node) and \
isinstance(upgradedNode.nodeDesc, SampleNodeV3)
assert not hasattr(upgradedNode, "paramA")
# check uid is identical (paramA not part of uid)
# Check UID is identical (paramA not part of UID)
assert upgradedNode.internalFolder == srcNode.internalFolder
elif isinstance(srcNode.nodeDesc, SampleNodeV3):
@ -282,9 +293,10 @@ def test_description_conflict():
assert len(compatNode.attributes) == 2
assert not hasattr(compatNode, "paramA")
# perform upgrade
# Perform upgrade
upgradedNode = g.upgradeNode(nodeName)
assert isinstance(upgradedNode, Node) and isinstance(upgradedNode.nodeDesc, SampleNodeV4)
assert isinstance(upgradedNode, Node) and \
isinstance(upgradedNode.nodeDesc, SampleNodeV4)
assert hasattr(upgradedNode, "paramA")
assert isinstance(upgradedNode.paramA.attributeDesc, desc.ListAttribute)
@ -298,22 +310,24 @@ def test_description_conflict():
groupAttribute = compatNode.paramA.attributeDesc.elementDesc
assert isinstance(groupAttribute, desc.GroupAttribute)
# check that Compatibility node respect SampleGroupV1 description
# Check that Compatibility node respect SampleGroupV1 description
for elt in groupAttribute.groupDesc:
assert isinstance(elt, next(a for a in SampleGroupV1 if a.name == elt.name).__class__)
assert isinstance(elt,
next(a for a in SampleGroupV1 if a.name == elt.name).__class__)
# perform upgrade
# Perform upgrade
upgradedNode = g.upgradeNode(nodeName)
assert isinstance(upgradedNode, Node) and isinstance(upgradedNode.nodeDesc, SampleNodeV5)
assert isinstance(upgradedNode, Node) and \
isinstance(upgradedNode.nodeDesc, SampleNodeV5)
assert hasattr(upgradedNode, "paramA")
# parameter was incompatible, value could not be restored
# Parameter was incompatible, value could not be restored
assert upgradedNode.paramA.isDefault
assert upgradedNode.internalFolder != srcNode.internalFolder
else:
raise ValueError("Unexpected node type: " + srcNode.nodeType)
# restore original node types
# Restore original node types
meshroom.core.nodesDesc = originalNodeTypes
@ -323,7 +337,7 @@ def test_upgradeAllNodes():
registerNodeType(SampleInputNodeV1)
registerNodeType(SampleInputNodeV2)
g = Graph('')
g = Graph("")
n1 = g.addNewNode("SampleNodeV1")
n2 = g.addNewNode("SampleNodeV2")
n3 = g.addNewNode("SampleInputNodeV1")
@ -335,28 +349,28 @@ def test_upgradeAllNodes():
graphFile = os.path.join(tempfile.mkdtemp(), "test_description_conflict.mg")
g.save(graphFile)
# make SampleNodeV2 and SampleInputNodeV2 an unknown type
# Make SampleNodeV2 and SampleInputNodeV2 an unknown type
unregisterNodeType(SampleNodeV2)
unregisterNodeType(SampleInputNodeV2)
# replace SampleNodeV1 by SampleNodeV2 and SampleInputNodeV1 by SampleInputNodeV2
meshroom.core.nodesDesc[SampleNodeV1.__name__] = SampleNodeV2
meshroom.core.nodesDesc[SampleInputNodeV1.__name__] = SampleInputNodeV2
# Replace SampleNodeV1 by SampleNodeV2 and SampleInputNodeV1 by SampleInputNodeV2
# reload file
# Reload file
g = loadGraph(graphFile)
os.remove(graphFile)
# both nodes are CompatibilityNodes
# Both nodes are CompatibilityNodes
assert len(g.compatibilityNodes) == 4
assert g.node(n1Name).canUpgrade # description conflict
assert not g.node(n2Name).canUpgrade # unknown type
assert g.node(n3Name).canUpgrade # description conflict
assert not g.node(n4Name).canUpgrade # unknown type
# upgrade all upgradable nodes
# Upgrade all upgradable nodes
g.upgradeAllNodes()
# only the nodes with an unknown type have not been upgraded
# Only the nodes with an unknown type have not been upgraded
assert len(g.compatibilityNodes) == 2
assert n2Name in g.compatibilityNodes.keys()
assert n4Name in g.compatibilityNodes.keys()
@ -369,36 +383,36 @@ def test_conformUpgrade():
registerNodeType(SampleNodeV5)
registerNodeType(SampleNodeV6)
g = Graph('')
g = Graph("")
n1 = g.addNewNode("SampleNodeV5")
n1.paramA.value = [{'a': 0, 'b': [{'a': 0, 'b': [1.0, 2.0]}, {'a': 1, 'b': [1.0, 2.0]}]}]
n1.paramA.value = [{"a": 0, "b": [{"a": 0, "b": [1.0, 2.0]}, {"a": 1, "b": [1.0, 2.0]}]}]
n1Name = n1.name
graphFile = os.path.join(tempfile.mkdtemp(), "test_conform_upgrade.mg")
g.save(graphFile)
# replace SampleNodeV5 by SampleNodeV6
# Replace SampleNodeV5 by SampleNodeV6
meshroom.core.nodesDesc[SampleNodeV5.__name__] = SampleNodeV6
# reload file
# Reload file
g = loadGraph(graphFile)
os.remove(graphFile)
# node is a CompatibilityNode
# Node is a CompatibilityNode
assert len(g.compatibilityNodes) == 1
assert g.node(n1Name).canUpgrade
# upgrade all upgradable nodes
# Upgrade all upgradable nodes
g.upgradeAllNodes()
# only the node with an unknown type has not been upgraded
# Only the node with an unknown type has not been upgraded
assert len(g.compatibilityNodes) == 0
upgradedNode = g.node(n1Name)
# check upgrade
# Check upgrade
assert isinstance(upgradedNode, Node) and isinstance(upgradedNode.nodeDesc, SampleNodeV6)
# check conformation
# Check conformation
assert len(upgradedNode.paramA.value) == 1
unregisterNodeType(SampleNodeV5)
@ -508,7 +522,8 @@ class UidTestingNodeV1(desc.Node):
inputs = [
desc.File(name="input", label="Input", description="", value="", invalidate=True),
]
outputs = [desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")]
outputs = [desc.File(name="output", label="Output",
description="", value="{nodeCacheFolder}")]
class UidTestingNodeV2(desc.Node):
@ -554,7 +569,8 @@ class UidTestingNodeV3(desc.Node):
description="",
),
]
outputs = [desc.File(name="output", label="Output", description="", value="{nodeCacheFolder}")]
outputs = [desc.File(name="output", label="Output",
description="", value="{nodeCacheFolder}")]
class TestUidConflict:
@ -626,7 +642,8 @@ class TestUidConflict:
assert len(loadedGraph.compatibilityNodes) == 0
def test_uidConflictDoesNotPropagateToValidDownstreamNodeThroughConnection(self, graphSavedOnDisk):
def test_uidConflictDoesNotPropagateToValidDownstreamNodeThroughConnection(
self, graphSavedOnDisk):
with registeredNodeTypes([UidTestingNodeV1, UidTestingNodeV2]):
graph: Graph = graphSavedOnDisk
nodeA = graph.addNewNode(UidTestingNodeV2.__name__)
@ -640,7 +657,8 @@ class TestUidConflict:
loadedGraph = loadGraph(graph.filepath)
assert len(loadedGraph.compatibilityNodes) == 1
def test_uidConflictDoesNotPropagateToValidDownstreamNodeThroughListConnection(self, graphSavedOnDisk):
def test_uidConflictDoesNotPropagateToValidDownstreamNodeThroughListConnection(
self,graphSavedOnDisk):
with registeredNodeTypes([UidTestingNodeV2, UidTestingNodeV3]):
graph: Graph = graphSavedOnDisk
nodeA = graph.addNewNode(UidTestingNodeV2.__name__)

View file

@ -2,11 +2,11 @@ from meshroom.core.graph import Graph
def test_depth():
graph = Graph('Tests tasks depth')
graph = Graph("Tests tasks depth")
tA = graph.addNewNode('Ls', input='/tmp')
tB = graph.addNewNode('AppendText', inputText='echo B')
tC = graph.addNewNode('AppendText', inputText='echo C')
tA = graph.addNewNode("Ls", input="/tmp")
tB = graph.addNewNode("AppendText", inputText="echo B")
tC = graph.addNewNode("AppendText", inputText="echo C")
graph.addEdges(
(tA.output, tB.input),
@ -19,12 +19,12 @@ def test_depth():
def test_depth_diamond_graph():
graph = Graph('Tests tasks depth')
graph = Graph("Tests tasks depth")
tA = graph.addNewNode('Ls', input='/tmp')
tB = graph.addNewNode('AppendText', inputText='echo B')
tC = graph.addNewNode('AppendText', inputText='echo C')
tD = graph.addNewNode('AppendFiles')
tA = graph.addNewNode("Ls", input="/tmp")
tB = graph.addNewNode("AppendText", inputText="echo B")
tC = graph.addNewNode("AppendText", inputText="echo C")
tD = graph.addNewNode("AppendFiles")
graph.addEdges(
(tA.output, tB.input),
@ -58,13 +58,13 @@ def test_depth_diamond_graph():
def test_depth_diamond_graph2():
graph = Graph('Tests tasks depth')
graph = Graph("Tests tasks depth")
tA = graph.addNewNode('Ls', input='/tmp')
tB = graph.addNewNode('AppendText', inputText='echo B')
tC = graph.addNewNode('AppendText', inputText='echo C')
tD = graph.addNewNode('AppendText', inputText='echo D')
tE = graph.addNewNode('AppendFiles')
tA = graph.addNewNode("Ls", input="/tmp")
tB = graph.addNewNode("AppendText", inputText="echo B")
tC = graph.addNewNode("AppendText", inputText="echo C")
tD = graph.addNewNode("AppendText", inputText="echo D")
tE = graph.addNewNode("AppendFiles")
# C
# / \
# /---/---->\
@ -116,14 +116,13 @@ def test_depth_diamond_graph2():
def test_transitive_reduction():
graph = Graph("Tests tasks depth")
graph = Graph('Tests tasks depth')
tA = graph.addNewNode('Ls', input='/tmp')
tB = graph.addNewNode('AppendText', inputText='echo B')
tC = graph.addNewNode('AppendText', inputText='echo C')
tD = graph.addNewNode('AppendText', inputText='echo D')
tE = graph.addNewNode('AppendFiles')
tA = graph.addNewNode("Ls", input="/tmp")
tB = graph.addNewNode("AppendText", inputText="echo B")
tC = graph.addNewNode("AppendText", inputText="echo C")
tD = graph.addNewNode("AppendText", inputText="echo D")
tE = graph.addNewNode("AppendFiles")
# C
# / \
# /---/---->\
@ -153,24 +152,24 @@ def test_transitive_reduction():
assert set(flowEdgesRes) == set(flowEdges)
assert len(graph._nodesMinMaxDepths) == len(graph.nodes)
for node, (minDepth, maxDepth) in graph._nodesMinMaxDepths.items():
for node, (_, maxDepth) in graph._nodesMinMaxDepths.items():
assert node.depth == maxDepth
def test_graph_reverse_dfsOnDiscover():
graph = Graph('Test dfsOnDiscover(reverse=True)')
graph = Graph("Test dfsOnDiscover(reverse=True)")
# ------------\
# / ~ C - E - F
# A - B
# ~ D
A = graph.addNewNode('Ls', input='/tmp')
B = graph.addNewNode('AppendText', inputText=A.output)
C = graph.addNewNode('AppendText', inputText=B.output)
D = graph.addNewNode('AppendText', inputText=B.output)
E = graph.addNewNode('Ls', input=C.output)
F = graph.addNewNode('AppendText', input=A.output, inputText=E.output)
A = graph.addNewNode("Ls", input="/tmp")
B = graph.addNewNode("AppendText", inputText=A.output)
C = graph.addNewNode("AppendText", inputText=B.output)
D = graph.addNewNode("AppendText", inputText=B.output)
E = graph.addNewNode("Ls", input=C.output)
F = graph.addNewNode("AppendText", input=A.output, inputText=E.output)
# Get all nodes from A (use set, order not guaranteed)
nodes = graph.dfsOnDiscover(startNodes=[A], reverse=True)[0]
@ -179,7 +178,7 @@ def test_graph_reverse_dfsOnDiscover():
nodes = graph.dfsOnDiscover(startNodes=[B], reverse=True)[0]
assert set(nodes) == {B, D, C, E, F}
# Get all nodes of type AppendText from B
nodes = graph.dfsOnDiscover(startNodes=[B], filterTypes=['AppendText'], reverse=True)[0]
nodes = graph.dfsOnDiscover(startNodes=[B], filterTypes=["AppendText"], reverse=True)[0]
assert set(nodes) == {B, D, C, F}
# Get all nodes from C (order guaranteed)
nodes = graph.dfsOnDiscover(startNodes=[C], reverse=True)[0]
@ -190,7 +189,7 @@ def test_graph_reverse_dfsOnDiscover():
def test_graph_dfsOnDiscover():
graph = Graph('Test dfsOnDiscover(reverse=False)')
graph = Graph("Test dfsOnDiscover(reverse=False)")
# ------------\
# / ~ C - E - F
@ -198,13 +197,13 @@ def test_graph_dfsOnDiscover():
# ~ D
# G
G = graph.addNewNode('Ls', input='/tmp')
A = graph.addNewNode('Ls', input='/tmp')
B = graph.addNewNode('AppendText', inputText=A.output)
C = graph.addNewNode('AppendText', inputText=B.output)
D = graph.addNewNode('AppendText', input=G.output, inputText=B.output)
E = graph.addNewNode('Ls', input=C.output)
F = graph.addNewNode('AppendText', input=A.output, inputText=E.output)
G = graph.addNewNode("Ls", input="/tmp")
A = graph.addNewNode("Ls", input="/tmp")
B = graph.addNewNode("AppendText", inputText=A.output)
C = graph.addNewNode("AppendText", inputText=B.output)
D = graph.addNewNode("AppendText", input=G.output, inputText=B.output)
E = graph.addNewNode("Ls", input=C.output)
F = graph.addNewNode("AppendText", input=A.output, inputText=E.output)
# Get all nodes from A (use set, order not guaranteed)
nodes = graph.dfsOnDiscover(startNodes=[A], reverse=False)[0]
@ -219,7 +218,7 @@ def test_graph_dfsOnDiscover():
nodes = graph.dfsOnDiscover(startNodes=[F], reverse=False)[0]
assert set(nodes) == {A, B, C, E, F}
# Get all nodes of type AppendText from C
nodes = graph.dfsOnDiscover(startNodes=[C], filterTypes=['AppendText'], reverse=False)[0]
nodes = graph.dfsOnDiscover(startNodes=[C], filterTypes=["AppendText"], reverse=False)[0]
assert set(nodes) == {B, C}
# Get all nodes from D (order guaranteed)
nodes = graph.dfsOnDiscover(startNodes=[D], longestPathFirst=True, reverse=False)[0]
@ -230,21 +229,21 @@ def test_graph_dfsOnDiscover():
def test_graph_nodes_sorting():
graph = Graph('')
graph = Graph("")
ls0 = graph.addNewNode('Ls')
ls1 = graph.addNewNode('Ls')
ls2 = graph.addNewNode('Ls')
ls0 = graph.addNewNode("Ls")
ls1 = graph.addNewNode("Ls")
ls2 = graph.addNewNode("Ls")
assert graph.nodesOfType('Ls', sortedByIndex=True) == [ls0, ls1, ls2]
assert graph.nodesOfType("Ls", sortedByIndex=True) == [ls0, ls1, ls2]
graph = Graph('')
graph = Graph("")
# 'Random' creation order (what happens when loading a file)
ls2 = graph.addNewNode('Ls', name='Ls_2')
ls0 = graph.addNewNode('Ls', name='Ls_0')
ls1 = graph.addNewNode('Ls', name='Ls_1')
ls2 = graph.addNewNode("Ls", name="Ls_2")
ls0 = graph.addNewNode("Ls", name="Ls_0")
ls1 = graph.addNewNode("Ls", name="Ls_1")
assert graph.nodesOfType('Ls', sortedByIndex=True) == [ls0, ls1, ls2]
assert graph.nodesOfType("Ls", sortedByIndex=True) == [ls0, ls1, ls2]
def test_duplicate_nodes():
@ -256,24 +255,25 @@ def test_duplicate_nodes():
# \ \
# ---------- n3
g = Graph('')
n0 = g.addNewNode('Ls', input='/tmp')
n1 = g.addNewNode('Ls', input=n0.output)
n2 = g.addNewNode('Ls', input=n1.output)
n3 = g.addNewNode('AppendFiles', input=n1.output, input2=n2.output)
g = Graph("")
n0 = g.addNewNode("Ls", input="/tmp")
n1 = g.addNewNode("Ls", input=n0.output)
n2 = g.addNewNode("Ls", input=n1.output)
n3 = g.addNewNode("AppendFiles", input=n1.output, input2=n2.output)
# duplicate from n1
# Duplicate from n1
nodes_to_duplicate, _ = g.dfsOnDiscover(startNodes=[n1], reverse=True, dependenciesOnly=True)
nMap = g.duplicateNodes(srcNodes=nodes_to_duplicate)
for s, duplicated in nMap.items():
for d in duplicated:
assert s.nodeType == d.nodeType
# check number of duplicated nodes and that every parent node has been duplicated once
assert len(nMap) == 3 and all([len(nMap[i]) == 1 for i in nMap.keys()])
# Check number of duplicated nodes and that every parent node has been duplicated once
assert len(nMap) == 3 and \
all([len(nMap[i]) == 1 for i in nMap.keys()])
# check connections
# access directly index 0 because we know there is a single duplicate for each parent node
# Check connections
# Access directly index 0 because we know there is a single duplicate for each parent node
assert nMap[n1][0].input.getLinkParam() == n0.output
assert nMap[n2][0].input.getLinkParam() == nMap[n1][0].output
assert nMap[n3][0].input.getLinkParam() == nMap[n1][0].output

View file

@ -255,7 +255,8 @@ class TestGraphPartialSerialization:
otherGraph = Graph("")
otherGraph._deserialize(graph.serializePartial([nodeA, nodeB]))
assert otherGraph.node(nodeB.name).listInput.linkParam == otherGraph.node(nodeA.name).listInput
assert otherGraph.node(nodeB.name).listInput.linkParam == \
otherGraph.node(nodeA.name).listInput
def test_singleNodeWithInputConnectionFromNonSerializedNodeRemovesEdge(self):
graph = Graph("")

View file

@ -7,8 +7,10 @@ from meshroom.core import desc, registerNodeType
class SampleNode(desc.Node):
""" Sample Node for unit testing """
inputs = [
desc.File(name='input', label='Input', description='', value='',),
desc.StringParam(name='paramA', label='ParamA', description='', value='', invalidate=False) # No impact on UID
desc.File(name="input", label="Input", description="", value="",),
desc.StringParam(name="paramA", label="ParamA",
description="", value="",
invalidate=False) # No impact on UID
]
outputs = [
desc.File(name='output', label='Output', description='', value="{nodeCacheFolder}")
@ -19,10 +21,10 @@ registerNodeType(SampleNode)
def test_output_invalidation():
graph = Graph('')
n1 = graph.addNewNode('SampleNode', input='/tmp')
n2 = graph.addNewNode('SampleNode')
n3 = graph.addNewNode('SampleNode')
graph = Graph("")
n1 = graph.addNewNode("SampleNode", input="/tmp")
n2 = graph.addNewNode("SampleNode")
n3 = graph.addNewNode("SampleNode")
graph.addEdges(
(n1.output, n2.input),
@ -52,9 +54,9 @@ def test_inputLinkInvalidation():
"""
Input links should not change the invalidation.
"""
graph = Graph('')
n1 = graph.addNewNode('SampleNode')
n2 = graph.addNewNode('SampleNode')
graph = Graph("")
n1 = graph.addNewNode("SampleNode")
n2 = graph.addNewNode("SampleNode")
graph.addEdges((n1.input, n2.input))
assert n1.input.uid() == n2.input.uid()

View file

@ -313,7 +313,8 @@ class TestAttributeCallbackBehaviorWithUpstreamCompoundAttributes:
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.
"""
inputs = [
@ -390,7 +391,6 @@ class TestAttributeCallbackBehaviorWithUpstreamDynamicOutputs:
assert nodeB.input.value == 20
assert nodeB.affectedInput.value == 0
def test_clearingDynamicOutputValueDoesNotTriggerDownstreamAttributeChangedCallback(
self, graphSavedOnDisk
):
@ -455,4 +455,3 @@ class TestAttributeCallbackBehaviorOnGraphImport:
otherGraph.importGraphContent(graph)
assert otherGraph.node(nodeB.name).affectedInput.value == 2

View file

@ -8,7 +8,8 @@ from meshroom.core.node import Node
class NodeWithAttributesNeedingFormatting(desc.Node):
"""
A node containing list, file, choice and group attributes in order to test the formatting of the command line.
A node containing list, file, choice and group attributes in order to test the
formatting of the command line.
"""
inputs = [
desc.ListAttribute(
@ -128,11 +129,14 @@ class TestCommandLineFormatting:
# Assert that extending values when the list is not empty is working
node.images.extend(inputImages)
assert node.images.getValueStr() == '"single value with space" "{}" "{}"'.format(inputImages[0],
assert node.images.getValueStr() == \
'"single value with space" "{}" "{}"'.format(inputImages[0],
inputImages[1])
# Values are not retrieved as strings in the command line, so quotes around them are not expected
assert node._cmdVars["imagesValue"] == 'single value with space {} {}'.format(inputImages[0],
# Values are not retrieved as strings in the command line, so quotes around them are
# not expected
assert node._cmdVars["imagesValue"] == \
'single value with space {} {}'.format(inputImages[0],
inputImages[1])
def test_formatting_strings(self):
@ -140,11 +144,13 @@ class TestCommandLineFormatting:
node = graph.addNewNode("NodeWithAttributesNeedingFormatting")
node._buildCmdVars()
# Assert an empty File attribute generates empty quotes when requesting its value as a string
# Assert an empty File attribute generates empty quotes when requesting its value as
# a string
assert node.input.getValueStr() == '""'
assert node._cmdVars["inputValue"] == ""
# Assert a Choice attribute with a non-empty default value is surrounded with quotes when requested as a string
# Assert a Choice attribute with a non-empty default value is surrounded with quotes
# when requested as a string
assert node.method.getValueStr() == '"MethodC"'
assert node._cmdVars["methodValue"] == "MethodC"
@ -154,14 +160,18 @@ class TestCommandLineFormatting:
# Assert that the list with one empty value generates empty quotes
node.images.extend("")
assert node.images.getValueStr() == '""', "A list with one empty string should generate empty quotes"
assert node._cmdVars["imagesValue"] == "", "The value is always only the value, so empty here"
assert node.images.getValueStr() == '""', \
"A list with one empty string should generate empty quotes"
assert node._cmdVars["imagesValue"] == "", \
"The value is always only the value, so empty here"
# Assert that a list with 2 empty strings generates quotes
node.images.extend("")
assert node.images.getValueStr() == '"" ""', "A list with 2 empty strings should generate quotes"
assert node.images.getValueStr() == '"" ""', \
"A list with 2 empty strings should generate quotes"
assert node._cmdVars["imagesValue"] == ' ', \
"The value is always only the value, so 2 empty strings with the space separator in the middle"
"The value is always only the value, so 2 empty strings with the " \
"space separator in the middle"
def test_formatting_groups(self):
graph = Graph("")

View file

@ -18,7 +18,7 @@ def registeredNodeTypes(nodeTypes: list[Type[desc.Node]]):
@contextmanager
def overrideNodeTypeVersion(nodeType: Type[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
with patch.object(
meshroom.core,