b1636bc781
Nested panels are not supported currently, and this parameter serves no actual purposes. Only the root panel supports adding child panels and it is not user-accessible (adding the root panel is done using a nullptr for the parent). Pull Request: https://projects.blender.org/blender/blender/pulls/118792
490 lines
21 KiB
Python
490 lines
21 KiB
Python
# SPDX-FileCopyrightText: 2021-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import pathlib
|
|
import sys
|
|
import unittest
|
|
import tempfile
|
|
|
|
import bpy
|
|
|
|
args = None
|
|
|
|
|
|
class AbstractNodeGroupInterfaceTest(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.testdir = args.testdir
|
|
cls._tempdir = tempfile.TemporaryDirectory()
|
|
cls.tempdir = pathlib.Path(cls._tempdir.name)
|
|
|
|
def setUp(self):
|
|
self.assertTrue(self.testdir.exists(),
|
|
'Test dir {0} should exist'.format(self.testdir))
|
|
|
|
# Make sure we always start with a known-empty file.
|
|
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "empty.blend"))
|
|
|
|
def tearDown(self):
|
|
self._tempdir.cleanup()
|
|
|
|
|
|
class NodeGroupInterfaceTests:
|
|
tree_type = None
|
|
group_node_type = None
|
|
# Tree instance where node groups can be added
|
|
main_tree = None
|
|
|
|
def make_group(self):
|
|
tree = bpy.data.node_groups.new("test", self.tree_type)
|
|
return tree
|
|
|
|
def make_instance(self, tree):
|
|
group_node = self.main_tree.nodes.new(self.group_node_type)
|
|
group_node.node_tree = tree
|
|
return group_node
|
|
|
|
def make_group_and_instance(self):
|
|
tree = self.make_group()
|
|
group_node = self.make_instance(tree)
|
|
return tree, group_node
|
|
|
|
# Utility method for generating a non-zero default value.
|
|
@staticmethod
|
|
def make_default_socket_value(socket_type):
|
|
if (socket_type == "NodeSocketBool"):
|
|
return True
|
|
elif (socket_type == "NodeSocketColor"):
|
|
return (.5, 1.0, .3, .7)
|
|
elif (socket_type == "NodeSocketFloat"):
|
|
return 1.23
|
|
elif (socket_type == "NodeSocketImage"):
|
|
return bpy.data.images.new("test", 4, 4)
|
|
elif (socket_type == "NodeSocketInt"):
|
|
return -6
|
|
elif (socket_type == "NodeSocketMaterial"):
|
|
return bpy.data.materials.new("test")
|
|
elif (socket_type == "NodeSocketObject"):
|
|
return bpy.data.objects.new("test", bpy.data.meshes.new("test"))
|
|
elif (socket_type == "NodeSocketRotation"):
|
|
return (0.3, 5.0, -42)
|
|
elif (socket_type == "NodeSocketString"):
|
|
return "Hello World!"
|
|
elif (socket_type == "NodeSocketTexture"):
|
|
return bpy.data.textures.new("test", 'MAGIC')
|
|
elif (socket_type == "NodeSocketVector"):
|
|
return (4.0, -1.0, 0.0)
|
|
|
|
# Utility method returning a comparator for socket values.
|
|
# Not all socket value types are trivially comparable, e.g. colors.
|
|
@staticmethod
|
|
def make_socket_value_comparator(socket_type):
|
|
def cmp_default(test, value, expected):
|
|
test.assertEqual(value, expected, f"Value {value} does not match expected value {expected}")
|
|
|
|
def cmp_array(test, value, expected):
|
|
test.assertSequenceEqual(value[:], expected[:], f"Value {value} does not match expected value {expected}")
|
|
|
|
if (socket_type in {"NodeSocketBool",
|
|
"NodeSocketFloat",
|
|
"NodeSocketImage",
|
|
"NodeSocketInt",
|
|
"NodeSocketMaterial",
|
|
"NodeSocketObject",
|
|
"NodeSocketRotation",
|
|
"NodeSocketString",
|
|
"NodeSocketTexture"}):
|
|
return cmp_default
|
|
elif (socket_type in {"NodeSocketColor",
|
|
"NodeSocketVector"}):
|
|
return cmp_array
|
|
|
|
def test_empty_nodegroup(self):
|
|
tree, group_node = self.make_group_and_instance()
|
|
|
|
self.assertFalse(tree.interface.items_tree, "Interface not empty")
|
|
self.assertFalse(group_node.inputs)
|
|
self.assertFalse(group_node.outputs)
|
|
|
|
def do_test_invalid_socket_type(self, socket_type):
|
|
tree = self.make_group()
|
|
|
|
with self.assertRaises(TypeError):
|
|
in0 = tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
self.assertIsNone(in0, f"Socket created for invalid type {socket_type}")
|
|
with self.assertRaises(TypeError):
|
|
out0 = tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
self.assertIsNone(out0, f"Socket created for invalid type {socket_type}")
|
|
|
|
def do_test_sockets_in_out(self, socket_type):
|
|
tree, group_node = self.make_group_and_instance()
|
|
|
|
out0 = tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
self.assertIsNotNone(out0, f"Could not create socket of type {socket_type}")
|
|
|
|
in0 = tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
self.assertIsNotNone(in0, f"Could not create socket of type {socket_type}")
|
|
|
|
in1 = tree.interface.new_socket("Input 1", socket_type=socket_type, in_out='INPUT')
|
|
self.assertIsNotNone(in1, f"Could not create socket of type {socket_type}")
|
|
|
|
out1 = tree.interface.new_socket("Output 1", socket_type=socket_type, in_out='OUTPUT')
|
|
self.assertIsNotNone(out1, f"Could not create socket of type {socket_type}")
|
|
|
|
self.assertSequenceEqual([(s.name, s.bl_idname) for s in group_node.inputs], [
|
|
("Input 0", socket_type),
|
|
("Input 1", socket_type),
|
|
])
|
|
self.assertSequenceEqual([(s.name, s.bl_idname) for s in group_node.outputs], [
|
|
("Output 0", socket_type),
|
|
("Output 1", socket_type),
|
|
])
|
|
|
|
def do_test_user_count(self, value, expected_users):
|
|
if (isinstance(value, bpy.types.ID)):
|
|
self.assertEqual(
|
|
value.users,
|
|
expected_users,
|
|
f"Socket default value has user count {value.users}, expected {expected_users}")
|
|
|
|
def do_test_socket_type(self, socket_type):
|
|
default_value = self.make_default_socket_value(socket_type)
|
|
compare_value = self.make_socket_value_comparator(socket_type)
|
|
|
|
# Create the tree first, add sockets, then create a group instance.
|
|
# That way the new instance should reflect the expected default values.
|
|
tree = self.make_group()
|
|
|
|
in0 = tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
if default_value is not None:
|
|
in0.default_value = default_value
|
|
out0 = tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
self.assertIsNotNone(in0, f"Could not create socket of type {socket_type}")
|
|
self.assertIsNotNone(out0, f"Could not create socket of type {socket_type}")
|
|
|
|
# Now make a node group instance to check default values.
|
|
group_node = self.make_instance(tree)
|
|
if compare_value:
|
|
compare_value(self, group_node.inputs[0].default_value, in0.default_value)
|
|
|
|
# Test ID user count after assigning.
|
|
if (hasattr(in0, "default_value")):
|
|
# The default value is stored in both the interface and node, it should have 2 users now.
|
|
self.do_test_user_count(in0.default_value, 2)
|
|
|
|
# Copy sockets
|
|
in1 = tree.interface.copy(in0)
|
|
out1 = tree.interface.copy(out0)
|
|
self.assertIsNotNone(in1, "Could not copy socket")
|
|
self.assertIsNotNone(out1, "Could not copy socket")
|
|
# User count on default values should increment by 2 after copy,
|
|
# one user for the interface and one for the group node instance.
|
|
if (hasattr(in1, "default_value")):
|
|
self.do_test_user_count(in1.default_value, 4)
|
|
|
|
# Classic outputs..inputs socket layout
|
|
def do_test_items_order_classic(self, socket_type):
|
|
tree, group_node = self.make_group_and_instance()
|
|
|
|
tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
|
|
self.assertSequenceEqual([(s.name, s.item_type) for s in tree.interface.items_tree], [
|
|
("Output 0", 'SOCKET'),
|
|
("Input 0", 'SOCKET'),
|
|
])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], [
|
|
"Input 0",
|
|
])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], [
|
|
"Output 0",
|
|
])
|
|
# XXX currently no panel state access on node instances.
|
|
# self.assertFalse(group_node.panels)
|
|
|
|
# Mixed sockets and panels
|
|
def do_test_items_order_mixed_with_panels(self, socket_type):
|
|
tree, group_node = self.make_group_and_instance()
|
|
|
|
tree.interface.new_panel("Panel 0")
|
|
tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
tree.interface.new_panel("Panel 1")
|
|
tree.interface.new_socket("Input 1", socket_type=socket_type, in_out='INPUT')
|
|
tree.interface.new_panel("Panel 2")
|
|
tree.interface.new_socket("Output 1", socket_type=socket_type, in_out='OUTPUT')
|
|
tree.interface.new_panel("Panel 3")
|
|
|
|
# Panels after sockets
|
|
self.assertSequenceEqual([(s.name, s.item_type) for s in tree.interface.items_tree], [
|
|
("Output 0", 'SOCKET'),
|
|
("Output 1", 'SOCKET'),
|
|
("Input 0", 'SOCKET'),
|
|
("Input 1", 'SOCKET'),
|
|
("Panel 0", 'PANEL'),
|
|
("Panel 1", 'PANEL'),
|
|
("Panel 2", 'PANEL'),
|
|
("Panel 3", 'PANEL'),
|
|
])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], [
|
|
"Input 0",
|
|
"Input 1",
|
|
])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], [
|
|
"Output 0",
|
|
"Output 1",
|
|
])
|
|
# XXX currently no panel state access on node instances.
|
|
# self.assertSequenceEqual([p.name for p in group_node.panels], [
|
|
# "Panel 0",
|
|
# "Panel 1",
|
|
# "Panel 2",
|
|
# "Panel 3",
|
|
# ])
|
|
|
|
def do_test_add(self, socket_type):
|
|
tree, group_node = self.make_group_and_instance()
|
|
|
|
in0 = tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
self.assertSequenceEqual(tree.interface.items_tree, [in0])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 0"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], [])
|
|
|
|
out0 = tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out0, in0])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 0"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 0"])
|
|
|
|
panel0 = tree.interface.new_panel("Panel 0")
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out0, in0, panel0])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 0"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 0"])
|
|
|
|
# Add items to the panel.
|
|
in1 = tree.interface.new_socket("Input 1", socket_type=socket_type, in_out='INPUT', parent=panel0)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out0, in0, panel0, in1])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 0", "Input 1"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 0"])
|
|
|
|
out1 = tree.interface.new_socket("Output 1", socket_type=socket_type, in_out='OUTPUT', parent=panel0)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out0, in0, panel0, out1, in1])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 0", "Input 1"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 0", "Output 1"])
|
|
|
|
def do_test_remove(self, socket_type):
|
|
tree, group_node = self.make_group_and_instance()
|
|
|
|
in0 = tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
out0 = tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
panel0 = tree.interface.new_panel("Panel 0")
|
|
in1 = tree.interface.new_socket("Input 1", socket_type=socket_type, in_out='INPUT', parent=panel0)
|
|
out1 = tree.interface.new_socket("Output 1", socket_type=socket_type, in_out='OUTPUT', parent=panel0)
|
|
panel1 = tree.interface.new_panel("Panel 1")
|
|
in2 = tree.interface.new_socket("Input 2", socket_type=socket_type, in_out='INPUT', parent=panel1)
|
|
out2 = tree.interface.new_socket("Output 2", socket_type=socket_type, in_out='OUTPUT', parent=panel1)
|
|
panel2 = tree.interface.new_panel("Panel 2")
|
|
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out0, in0, panel0, out1, in1, panel1, out2, in2, panel2])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 0", "Input 1", "Input 2"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 0", "Output 1", "Output 2"])
|
|
|
|
# Remove from root panel.
|
|
tree.interface.remove(in0)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out0, panel0, out1, in1, panel1, out2, in2, panel2])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 1", "Input 2"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 0", "Output 1", "Output 2"])
|
|
|
|
# Removing a panel should move content to the parent.
|
|
tree.interface.remove(panel0)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out0, out1, in1, panel1, out2, in2, panel2])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 1", "Input 2"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 0", "Output 1", "Output 2"])
|
|
|
|
tree.interface.remove(out0)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out1, in1, panel1, out2, in2, panel2])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 1", "Input 2"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 1", "Output 2"])
|
|
|
|
# Remove content from panel
|
|
tree.interface.remove(out2)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out1, in1, panel1, in2, panel2])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 1", "Input 2"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 1"])
|
|
|
|
# Remove a panel and its content
|
|
tree.interface.remove(panel1, move_content_to_parent=False)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out1, in1, panel2])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 1"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 1"])
|
|
|
|
# Remove empty panel
|
|
tree.interface.remove(panel2)
|
|
self.assertSequenceEqual(tree.interface.items_tree, [out1, in1])
|
|
self.assertSequenceEqual([s.name for s in group_node.inputs], ["Input 1"])
|
|
self.assertSequenceEqual([s.name for s in group_node.outputs], ["Output 1"])
|
|
|
|
def do_test_move(self, socket_type):
|
|
tree, group_node = self.make_group_and_instance()
|
|
|
|
in0 = tree.interface.new_socket("Input 0", socket_type=socket_type, in_out='INPUT')
|
|
in1 = tree.interface.new_socket("Input 1", socket_type=socket_type, in_out='INPUT', parent=panel0)
|
|
out0 = tree.interface.new_socket("Output 0", socket_type=socket_type, in_out='OUTPUT')
|
|
out1 = tree.interface.new_socket("Output 1", socket_type=socket_type, in_out='OUTPUT', parent=panel0)
|
|
panel0 = tree.interface.new_panel("Panel 0")
|
|
panel1 = tree.interface.new_panel("Panel 1")
|
|
|
|
|
|
class GeometryNodeGroupInterfaceTest(AbstractNodeGroupInterfaceTest, NodeGroupInterfaceTests):
|
|
tree_type = "GeometryNodeTree"
|
|
group_node_type = "GeometryNodeGroup"
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.main_tree = bpy.data.node_groups.new("main", self.tree_type)
|
|
|
|
def test_sockets_in_out(self):
|
|
self.do_test_sockets_in_out("NodeSocketFloat")
|
|
|
|
def test_all_socket_types(self):
|
|
self.do_test_invalid_socket_type("INVALID_SOCKET_TYPE_11!1")
|
|
self.do_test_socket_type("NodeSocketBool")
|
|
self.do_test_socket_type("NodeSocketCollection")
|
|
self.do_test_socket_type("NodeSocketColor")
|
|
self.do_test_socket_type("NodeSocketFloat")
|
|
self.do_test_socket_type("NodeSocketGeometry")
|
|
self.do_test_socket_type("NodeSocketImage")
|
|
self.do_test_socket_type("NodeSocketInt")
|
|
self.do_test_socket_type("NodeSocketMaterial")
|
|
self.do_test_socket_type("NodeSocketObject")
|
|
self.do_test_socket_type("NodeSocketRotation")
|
|
self.do_test_invalid_socket_type("NodeSocketShader")
|
|
self.do_test_socket_type("NodeSocketString")
|
|
self.do_test_socket_type("NodeSocketTexture")
|
|
self.do_test_socket_type("NodeSocketVector")
|
|
self.do_test_invalid_socket_type("NodeSocketVirtual")
|
|
|
|
def test_items_order_classic(self):
|
|
self.do_test_items_order_classic("NodeSocketFloat")
|
|
|
|
def test_items_order_mixed_with_panels(self):
|
|
self.do_test_items_order_mixed_with_panels("NodeSocketFloat")
|
|
|
|
def test_add(self):
|
|
self.do_test_add("NodeSocketFloat")
|
|
|
|
def test_remove(self):
|
|
self.do_test_remove("NodeSocketFloat")
|
|
|
|
|
|
class ShaderNodeGroupInterfaceTest(AbstractNodeGroupInterfaceTest, NodeGroupInterfaceTests):
|
|
tree_type = "ShaderNodeTree"
|
|
group_node_type = "ShaderNodeGroup"
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.material = bpy.data.materials.new("test")
|
|
self.material.use_nodes = True
|
|
self.main_tree = self.material.node_tree
|
|
|
|
def test_invalid_socket_type(self):
|
|
self.do_test_invalid_socket_type("INVALID_SOCKET_TYPE_11!1")
|
|
|
|
def test_sockets_in_out(self):
|
|
self.do_test_sockets_in_out("NodeSocketFloat")
|
|
|
|
def test_all_socket_types(self):
|
|
self.do_test_socket_type("NodeSocketBool")
|
|
self.do_test_invalid_socket_type("NodeSocketCollection")
|
|
self.do_test_socket_type("NodeSocketColor")
|
|
self.do_test_socket_type("NodeSocketFloat")
|
|
self.do_test_invalid_socket_type("NodeSocketGeometry")
|
|
self.do_test_invalid_socket_type("NodeSocketImage")
|
|
self.do_test_socket_type("NodeSocketInt")
|
|
self.do_test_invalid_socket_type("NodeSocketMaterial")
|
|
self.do_test_invalid_socket_type("NodeSocketObject")
|
|
self.do_test_invalid_socket_type("NodeSocketRotation")
|
|
self.do_test_socket_type("NodeSocketShader")
|
|
self.do_test_invalid_socket_type("NodeSocketString")
|
|
self.do_test_invalid_socket_type("NodeSocketTexture")
|
|
self.do_test_socket_type("NodeSocketVector")
|
|
self.do_test_invalid_socket_type("NodeSocketVirtual")
|
|
|
|
def test_items_order_classic(self):
|
|
self.do_test_items_order_classic("NodeSocketFloat")
|
|
|
|
def test_items_order_mixed_with_panels(self):
|
|
self.do_test_items_order_mixed_with_panels("NodeSocketFloat")
|
|
|
|
def test_add(self):
|
|
self.do_test_add("NodeSocketFloat")
|
|
|
|
def test_remove(self):
|
|
self.do_test_remove("NodeSocketFloat")
|
|
|
|
|
|
class CompositorNodeGroupInterfaceTest(AbstractNodeGroupInterfaceTest, NodeGroupInterfaceTests):
|
|
tree_type = "CompositorNodeTree"
|
|
group_node_type = "CompositorNodeGroup"
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.scene = bpy.data.scenes.new("test")
|
|
self.scene.use_nodes = True
|
|
self.main_tree = self.scene.node_tree
|
|
|
|
def test_invalid_socket_type(self):
|
|
self.do_test_invalid_socket_type("INVALID_SOCKET_TYPE_11!1")
|
|
|
|
def test_sockets_in_out(self):
|
|
self.do_test_sockets_in_out("NodeSocketFloat")
|
|
|
|
def test_all_socket_types(self):
|
|
self.do_test_invalid_socket_type("NodeSocketBool")
|
|
self.do_test_invalid_socket_type("NodeSocketCollection")
|
|
self.do_test_socket_type("NodeSocketColor")
|
|
self.do_test_socket_type("NodeSocketFloat")
|
|
self.do_test_invalid_socket_type("NodeSocketGeometry")
|
|
self.do_test_invalid_socket_type("NodeSocketImage")
|
|
self.do_test_invalid_socket_type("NodeSocketInt")
|
|
self.do_test_invalid_socket_type("NodeSocketMaterial")
|
|
self.do_test_invalid_socket_type("NodeSocketObject")
|
|
self.do_test_invalid_socket_type("NodeSocketRotation")
|
|
self.do_test_invalid_socket_type("NodeSocketShader")
|
|
self.do_test_invalid_socket_type("NodeSocketString")
|
|
self.do_test_invalid_socket_type("NodeSocketTexture")
|
|
self.do_test_socket_type("NodeSocketVector")
|
|
self.do_test_invalid_socket_type("NodeSocketVirtual")
|
|
|
|
def test_items_order_classic(self):
|
|
self.do_test_items_order_classic("NodeSocketFloat")
|
|
|
|
def test_items_order_mixed_with_panels(self):
|
|
self.do_test_items_order_mixed_with_panels("NodeSocketFloat")
|
|
|
|
def test_add(self):
|
|
self.do_test_add("NodeSocketFloat")
|
|
|
|
def test_remove(self):
|
|
self.do_test_remove("NodeSocketFloat")
|
|
|
|
|
|
def main():
|
|
global args
|
|
import argparse
|
|
|
|
if '--' in sys.argv:
|
|
argv = [sys.argv[0]] + sys.argv[sys.argv.index('--') + 1:]
|
|
else:
|
|
argv = sys.argv
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--testdir', required=True, type=pathlib.Path)
|
|
args, remaining = parser.parse_known_args(argv)
|
|
|
|
unittest.main(argv=remaining)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|