Skip to content

Commit

Permalink
Implement MDGModifier::disconnect binding
Browse files Browse the repository at this point in the history
  • Loading branch information
yantor3d committed May 31, 2021
1 parent eb79c64 commit 2f70015
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 29 deletions.
52 changes: 50 additions & 2 deletions src/MDGModifier.inl
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,59 @@ operation is added so that the queue is emptied. Then, deleteNode() can be calle
doIt() should be called immediately after to ensure that the queue is emptied before any other operations are added to it.)pbdoc")

.def("disconnect", [](MDGModifier & self, MObject sourceNode, MObject sourceAttr, MObject destNode, MObject destAttr) {
throw std::logic_error{"Function not yet implemented."};
if (sourceNode.isNull())
{
throw std::invalid_argument("Cannot disconnect - sourceNode is null.");
} else if (!sourceNode.hasFn(MFn::kDependencyNode)) {
MString error_msg("Cannot disconnect - sourceNode must be a 'node' object , not a '^1s' object.");
error_msg.format(error_msg, sourceNode.apiTypeStr());
throw pybind11::type_error(error_msg.asChar());
}

if (sourceAttr.isNull())
{
throw std::invalid_argument("Cannot disconnect - sourceAttr is null.");
} else if (!sourceAttr.hasFn(MFn::kAttribute)) {
MString error_msg("Cannot add attribute - sourceAttr must be a 'kAttribute' object, not a(n) '^1s' object.");
error_msg.format(error_msg, sourceAttr.apiTypeStr());
throw pybind11::type_error(error_msg.asChar());
}

if (destNode.isNull())
{
throw std::invalid_argument("Cannot disconnect - destNode is null.");
} else if (!destNode.hasFn(MFn::kDependencyNode)) {
MString error_msg("Cannot disconnect - destNode must be a 'kDependencyNode' object , not a '^1s' object.");
error_msg.format(error_msg, destNode.apiTypeStr());
throw pybind11::type_error(error_msg.asChar());
}

if (destAttr.isNull())
{
throw std::invalid_argument("Cannot disconnect - destAttr is null.");
} else if (!destAttr.hasFn(MFn::kAttribute)) {
MString error_msg("Cannot add attribute - destAttr must be a 'kAttribute' object, not a(n) '^1s' object.");
error_msg.format(error_msg, destAttr.apiTypeStr());
throw pybind11::type_error(error_msg.asChar());
}

MStatus status = self.disconnect(sourceNode, sourceAttr, destNode, destAttr);
CHECK_STATUS(status)
}, R"pbdoc(Adds an operation to the modifier that breaks a connection between two plugs in the dependency graph.)pbdoc")

.def("disconnect", [](MDGModifier & self, MPlug source, MPlug dest) {
throw std::logic_error{"Function not yet implemented."};
if (source.isNull())
{
throw std::invalid_argument("Cannot disconnect - source is null.");
}

if (dest.isNull())
{
throw std::invalid_argument("Cannot disconnect - dest is null.");
}

MStatus status = self.disconnect(source, dest);
CHECK_STATUS(status)
}, R"pbdoc(Adds an operation to the modifier that breaks a connection between two plugs in the dependency graph.)pbdoc")

.def("doIt", [](MDGModifier & self) {
Expand Down
134 changes: 107 additions & 27 deletions tests/test_MDGModifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,31 @@ def _addAttribute_fail(exception, node, attr):
)


@nose.with_setup(teardown=new_scene)
def test_connect_pass():
src_plug = as_plug(cmds.createNode('transform') + '.visibility')
dst_plug = as_plug(cmds.createNode('transform') + '.visibility')

for doc, args in (
["plugs", (src_plug, dst_plug)],
["node/attribute pairs", (src_plug.node(), src_plug.attribute(), dst_plug.node(), dst_plug.attribute())]
):
test_connect_pass.__doc__ = """Test MDGModifier::connect if called with {}.""".format(doc)

yield _connect_pass, src_plug, dst_plug, args


def _connect_pass(src_plug, dst_plug, args):
mod = cmdc.DGModifier()
mod.connect(*args)

mod.doIt()
assert cmds.isConnected(src_plug.name(), dst_plug.name()), "DGModifier.connect doIt failed"

mod.undoIt()
assert not cmds.isConnected(src_plug.name(), dst_plug.name()), 'DGModifier.connect undoIt failed'


@nose.with_setup(teardown=new_scene)
def test_connect_fail():
src_plug = as_plug(cmds.createNode('transform') + '.visibility')
Expand Down Expand Up @@ -78,31 +103,6 @@ def _connect_fail(exception, args):
)


@nose.with_setup(teardown=new_scene)
def test_connect_pass():
src_plug = as_plug(cmds.createNode('transform') + '.visibility')
dst_plug = as_plug(cmds.createNode('transform') + '.visibility')

for doc, args in (
["plugs", (src_plug, dst_plug)],
["node/attribute pairs", (src_plug.node(), src_plug.attribute(), dst_plug.node(), dst_plug.attribute())]
):
test_connect_pass.__doc__ = """Test MDGModifier::connect if called with {}.""".format(doc)

yield _connect_pass, src_plug, dst_plug, args


def _connect_pass(src_plug, dst_plug, args):
mod = cmdc.DGModifier()
mod.connect(*args)

mod.doIt()
assert cmds.isConnected(src_plug.name(), dst_plug.name()), "DGModifier.connect doIt failed"

mod.undoIt()
assert not cmds.isConnected(src_plug.name(), dst_plug.name()), 'DGModifier.connect undoIt failed'


def test_createNode_pass():
node = as_obj(cmds.createNode('network'))
type_id = cmdc.FnDependencyNode(node).typeId()
Expand All @@ -111,7 +111,7 @@ def test_createNode_pass():
['typeName', 'network'],
['typeId', cmdc.TypeId(type_id)]
):
test_createNode_pass.__doc__ = """Test for MDGModifier::createNode if called with a valid {}.""".format(name)
test_createNode_pass.__doc__ = """Test MDGModifier::createNode if called with a valid {}.""".format(name)

yield _createNode_pass, value

Expand All @@ -121,7 +121,7 @@ def test_createNode_fail():
['typeName', 'foobar'],
['typeId', cmdc.TypeId(0xdeadbeef)]
):
test_createNode_fail.__doc__ = """Test MDGModifier::createNode if called with an invalid {}.""".format(name)
test_createNode_fail.__doc__ = """Test MDGModifier::createNode raises error if called with an invalid {}.""".format(name)

yield _createNode_fail, value

Expand Down Expand Up @@ -153,3 +153,83 @@ def _createNode_pass(arg):

assert not node.isNull(), "Created node is not valid."
assert len(add_nodes) == 1, "`ls` did not return new node."



def test_disconnect_pass():
def _plugs():
src_plug = as_plug(cmds.createNode('transform') + '.visibility')
dst_plug = as_plug(cmds.createNode('transform') + '.visibility')

return (
src_plug, dst_plug,
(src_plug, dst_plug)
)

def _objects():
src_plug = as_plug(cmds.createNode('transform') + '.visibility')
dst_plug = as_plug(cmds.createNode('transform') + '.visibility')

return (
src_plug, dst_plug,
(src_plug.node(), src_plug.attribute(), dst_plug.node(), dst_plug.attribute())
)

for doc, setup_fn in (
["plugs", _plugs],
["node/attribute pairs", _objects]
):
test_disconnect_pass.__doc__ = """Test MDGModifier::disconnect if called with {}.""".format(doc)

yield _disconnect_pass, setup_fn


@nose.with_setup(teardown=new_scene)
def _disconnect_pass(setup_fn):
src_plug, dst_plug, args = setup_fn()
cmds.connectAttr(src_plug.name(), dst_plug.name())

mod = cmdc.DGModifier()
mod.disconnect(*args)

mod.doIt()
assert not cmds.isConnected(src_plug.name(), dst_plug.name()), "DGModifier.disconnect doIt failed"

mod.undoIt()
assert cmds.isConnected(src_plug.name(), dst_plug.name()), 'DGModifier.disconnect undoIt failed'


def test_disconnect_fail():
src_plug = as_plug(cmds.createNode('transform') + '.visibility')
src_node = src_plug.node()
src_attr = src_plug.attribute()

dst_plug = as_plug(cmds.createNode('transform') + '.visibility')
dst_node = dst_plug.node()
dst_attr = dst_plug.attribute()

null = cmdc.Object()
nop_plug = cmdc.Plug()

for exc, doc, args in (
[ValueError, 'a null source object', (null, null, null, null)],
[ValueError, 'a null source attribute', (src_node, null, null, null)],
[ValueError, 'a null destination object', (src_node, src_attr, null, null)],
[ValueError, 'a null destination attribute', (src_node, src_attr, dst_node, null)],
[TypeError, 'a non-node source object', (src_attr, src_attr, null, null)],
[TypeError, 'a non-attribute source attribute',(src_node, src_node, null, null)],
[TypeError, 'a non-node destination object', (src_node, src_attr, dst_attr, dst_attr)],
[TypeError, 'a non-attribute destination attribute', (src_node, src_attr, dst_node, dst_node)],
[ValueError, 'a null source plug', (nop_plug, dst_plug)],
[ValueError, 'a null destination plug', (src_plug, nop_plug)],
):
test_disconnect_fail.__doc__ = """Test MDGModifier::disconnect raises exception if called with {}.""".format(doc)

yield _disconnect_fail, exc, args

def _disconnect_fail(exception, args):
nose.tools.assert_raises(
exception,
cmdc.DGModifier().disconnect,
*args
)

0 comments on commit 2f70015

Please sign in to comment.