def create(cls): """Create a new Network node with storage node capabilities""" n = nt.Network() n.addAttribute( persistence.createStorageAttribute( persistence.PyPickleData.kPluginDataId)) return StorageNetworkNode(n.object())
def test_replace_non_leaf_node_types(self): # keep the previous type as we want to restore it OldDependNode = nt.DependNode nold = nt.Network() assert str(nold).startswith("network") # overwriting the foundation of all nodes will not change anything # for existing node types, as they have bound the previous type already. class DependNode(nt.Node): """This type cannot do anything, we have removed functionality""" def __str__(self): return 'me_as_string' # END custom DependNode assert str(nold).startswith('network') # new instances still use the default implementation nnew = nt.Network() assert str(nnew).startswith('network') # also we cannot instatiate it explicitly as we are not inheriting # from the type that MRV wants to create, Network self.failUnlessRaises(TypeError, DependNode, nnew.object()) # we could get away with this, but we clean it up anyway nt.removeCustomType(DependNode) nt.addCustomType(OldDependNode) # MONKEY PATCHING ################# # The only way to get custom method implementation directly into the non-leaf # node types is monkey patching, hence existing methods will be overwritten # with your implementation # Using the dict for retrieval as one would get class methods otherwise, these # check for the actual type passed in which would fail in our case. old_str = nt.DependNode.__dict__['__str__'] nt.DependNode.__str__ = DependNode.__dict__['__str__'] assert str(nold) == 'me_as_string' # undo our changes nt.DependNode.__str__ = old_str
def test_namespace_adjustment(self): dag = nt.Transform() dg = nt.Network() childns = nsm.Namespace.create(":foo:bar") parentns = childns.parent() for node in (dag, dg): assert node.namespace() == nsm.RootNamespace assert isinstance(node.setNamespace(childns), nt.Node) assert node.namespace() == childns assert node.setNamespace(parentns).namespace() == parentns assert node.setNamespace(nsm.RootNamespace).namespace() == nsm.RootNamespace
def test_virtual_subtype(self): n = nt.Network() # types must define the __mrv_virtual_subtype__ attribute self.failUnlessRaises(TypeError, StorageNetworkNodeWrong, n.object()) # make a StorageNetwork node sn = StorageNetworkNode.create() assert isinstance(sn, StorageNetworkNode) # it cannot wrap ordinary network nodes - we implemented it that way self.failUnlessRaises(TypeError, StorageNetworkNode, n.object()) # iteration works fine as well sns = list(StorageNetworkNode.iter_instances()) assert len(sns) == 1 and isinstance(sns[0], StorageNetworkNode) assert sns[0] == sn # be sure we can use the storage interface assert isinstance(sn.dataIDs(), list)
def test_replacing_default_node_types(self): n = nt.Network() sn = StorageNetworkNode.create() # REPLACING BUILTIN NODE TYPES ############################## # if we want to play crazy, we can make all network nodes our special # storage node, be replacing the existing Network node type. # Any instantiation will fail as if its not one of our specialized nodes, # but this is implementation defined of course. # Defining a new derived Type automatically puts it into the nt module OldNetwork = nt.Network class Network(StorageNetworkNode): def sayhello(self): print "hello" # yes, the official Network node is now our own one, automatically assert nt.Network is Network sn2 = nt.Node(str(sn)) assert isinstance(sn2, StorageNetworkNode) assert isinstance(sn2.dataIDs(), list) # and it can say something sn2.sayhello() # we cannot wrap normal nodes as our initializer on StorageNetworkNode barks # if the vital data plug cannot be found. self.failUnlessRaises(TypeError, nt.Node, str(n)) # reset the old one, we affect everything within MRV now nt.removeCustomType(Network) nt.addCustomType(OldNetwork) # everything back to normal - we get plain old network nodes sn_network = nt.Node(sn.object()) assert type(sn_network) is OldNetwork assert type(sn_network) is nt.Network # REPLACING BUILTIN NODES PROPERLY ################################## class Network(OldNetwork, nt.StorageBase): def __init__(self, node): """Implement the initializer such that we only initialize our base if we have the 'data' attribute. Otherwise we keep it uninitialized, so it will not be functional""" try: super(Network, self).__init__(node) except TypeError: pass # END handle input type def sayaloha(self): print "aloha" # END better Super-Network implementation assert nt.Network is Network # now plain network nodes will be new Network nodes, but we are allowed # to create them # NodeFromObj works as well, just to be sure n2 = nt.NodeFromObj(n.object()) assert type(n2) is Network # as the storage base has not been initialized, we cannot do anything # with it. The actual point here though is that users who don't know the # interface will get a fully functional network node at least. # As we do not 'tighten' the interface, code that doesn't expect our type # will not get into trouble. self.failUnlessRaises(AttributeError, n2.dataIDs) assert isinstance(n2, OldNetwork) n2.sayaloha() # and storage network nodes will be 'Network' nodes whose additional # functions we can use sn2 = nt.Node(sn.object()) assert type(sn2) is Network sn2.sayaloha() sn2.dataIDs() # once again, get rid of our custom type, reset the old one nt.removeCustomType(Network) nt.addCustomType(OldNetwork) assert nt.Network is OldNetwork
def test_MPlug(self): persp = nt.Node("persp") front = nt.Node("front") side = nt.Node("side") matworld = persp.worldMatrix assert isinstance(matworld.mfullyQualifiedName(), basestring) str(matworld) repr(matworld) # CONNECTIONS ####################### # CHECK COMPOUND ACCESS tx = persp.translate.mchildByName('tx') # can access attributes twice persp.translate # DO CONNECTIONS ( test undo/redo ) persp.translate.mconnectTo(front.translate, force=True) assert persp.translate.misConnectedTo( front.translate) # misConnectedTo assert persp.translate.minput().isNull() cmds.undo() assert not persp.translate.misConnectedTo(front.translate) cmds.redo() assert front.translate in persp.translate.moutputs() # check moutput assert persp.translate.moutput() == front.translate assert persp.rotate.moutput().isNull( ) # unconnected return nullPlus as minput does # CHECK CONNECTION FORCING persp.translate.mconnectTo(front.translate, force=False) # already connected self.failUnlessRaises(RuntimeError, persp.s.mconnectTo, front.translate, force=False) # overwrite connection side.translate.mconnectTo(front.translate) # force default True assert side.translate.misConnectedTo(front.translate) # undo - old connection should be back cmds.undo() assert persp.translate.misConnectedTo(front.translate) # disconnect input front.translate.mdisconnectInput() assert not persp.translate.misConnectedTo(front.translate) cmds.undo() # disconnect output persp.t.mdisconnectOutputs() assert len(persp.translate.moutputs()) == 0 cmds.undo() assert persp.t.misConnectedTo(front.translate) # disconnect from persp.t.mdisconnectFrom(front.translate) assert not persp.t.misConnectedTo(front.t) cmds.undo() assert persp.t.misConnectedTo(front.t) # COMPARISONS assert persp.t != front.t assert persp.t.mchildByName('tx') != persp.t.mchildByName('ty') # affected plugs affectedPlugs = persp.t.maffects() assert len(affectedPlugs) > 1 affectedPlugs = persp.t.maffected() assert len(affectedPlugs) > 1 # test multi connections sn = nt.createNode("network1", "network") sn2 = nt.createNode("network2", "network") tn = nt.createNode("network3", "network") def pir(array_plug, range_iter): for index in range_iter: yield array_plug.elementByLogicalIndex(index) # END for each item in range # END plugs-in-range # connect 10 to 10 r = range(10) api.MPlug.mconnectMultiToMulti(izip(pir(sn.a, r), pir(tn.affectedBy, r)), force=False) for i in r: assert sn.a.elementByLogicalIndex(i).misConnectedTo( tn.affectedBy.elementByLogicalIndex(i)) # END make connection assertion # connection of overlapping range fails without force r = range(5, 15) self.failUnlessRaises(RuntimeError, api.MPlug.mconnectMultiToMulti, izip(pir(sn2.a, r), pir(tn.affectedBy, r)), force=False) # there no connection should have worked ( its atomic ) # hence slot 10 is free persp.tx > tn.affectedBy.elementByLogicalIndex(10) # force connection works api.MPlug.mconnectMultiToMulti(izip(pir(sn2.a, r), pir(tn.affectedBy, r)), force=True) for i in r: assert sn2.a.elementByLogicalIndex(i).misConnectedTo( tn.affectedBy.elementByLogicalIndex(i)) # END make connection assertion # ATTRIBUTES AND UNDO ####################### funcs = (("isLocked", "msetLocked"), ("isKeyable", "msetKeyable"), ("isCachingFlagSet", "msetCaching"), ("isChannelBoxFlagSet", "msetChannelBox")) plugnames = ("t", "tx", "r", "rx", "s", "sy") for p in plugnames: plug = persp.findPlug(p) for (getname, setname) in funcs: fget = getattr(plug, getname) fset = getattr(plug, setname) curval = fget() oval = bool(1 - curval) fset(oval) # SPECIAL HANDLING as things cannot be uncached if setname == "msetCaching": continue assert fget() == oval cmds.undo() assert fget() == curval cmds.redo() assert fget() == oval fset(curval) # reset # END for each function # END for each plugname # QUERY ############################ # ELEMENT ITERATION matworld.evaluateNumElements() for elm in matworld: assert elm.mparent() == matworld translate = persp.translate assert len(translate.mchildren()) == translate.numChildren() # CHILD ITERATION for child in translate.mchildren(): assert child.mparent() == translate assert len(translate.mchildren()) == 3 # SUB PLUGS GENERAL METHOD assert len(matworld) == len(matworld.msubPlugs()) assert translate.numChildren() == len(translate.msubPlugs()) assert len(translate.msubPlugs()) == 3 # ARRAY CONNECTIONS ################### objset = nt.createNode("set1", "objectSet") partition = nt.createNode("partition1", "partition") pma = nt.createNode("plusMinusAverage1", "plusMinusAverage") destplug = persp.translate.mconnectToArray(pma.input3D, exclusive_connection=True) assert persp.translate.misConnectedTo(destplug) # exclusive connection should return exisiting plug assert persp.translate.mconnectToArray( pma.input3D, exclusive_connection=True) == destplug # but newones can also be created assert persp.translate.mconnectToArray( pma.input3D, exclusive_connection=False) != destplug #assert objset.partition.mconnectToArray( partition.sets, exclusive_connection = False ) != destplug # assure the standin classes are there - otherwise my list there would # bind to the standins as the classes have not been created yet plugs = [matworld, translate] for plug in plugs: plug.mwrappedAttribute() # CHECK ATTRIBUTES and NODES for plug, attrtype in zip(plugs, [nt.TypedAttribute, nt.CompoundAttribute]): attr = plug.mwrappedAttribute() assert isinstance(attr, nt.Attribute) assert isinstance(attr, attrtype) node = plug.mwrappedNode() assert isinstance(node, nt.Node) assert node == persp # UNDO / REDO ############## cam = nt.createNode("myTrans", "transform") testdb = [(cam.visibility, "Bool", True, False), (cam.tx, "Double", 0.0, 2.0)] # TODO: Add all missing types ! for plug, typename, initialval, targetval in testdb: getattrfunc = getattr(plug, "as" + typename) setattrfunc = getattr(plug, "mset" + typename) assert getattrfunc() == initialval setattrfunc(targetval) assert getattrfunc() == targetval cmds.undo() assert getattrfunc() == initialval cmds.redo() assert getattrfunc() == targetval # END for each tuple in testdb # TEST EVERYTHING ################# # This part has been written to be very sure every customized method gets # called at least once. I don't trust my 'old' tests, although they do # something and are valuable to the testing framework. nwnode = nt.Network() persp.msg.mct(nwnode.affectedBy.elementByLogicalIndex(0)) front.msg.mct(nwnode.affectedBy.elementByLogicalIndex(1)) t = persp.translate tx = persp.tx wm = persp.wm a = nwnode.affectedBy a.evaluateNumElements() assert len(wm) == 1 and len(a) == 2 assert isinstance(iter(wm).next(), api.MPlug) assert len(list(a)) == 2 # test str/repr assert str(wm) != str(a) assert repr(wm) != str(wm) assert wm != a # is it really necessary to apply custom handling here ? Check __eq__ method # test comparison assert a[0] == a[0] assert a[0] != a[1] # mparent assert tx.mparent() == t assert a[0].mparent() == a # mchildren assert len(a[0].mchildren()) == 0 assert len(t.mchildren()) == 3 # mchildByName assert t.mchildByName('tx') == tx self.failUnlessRaises(TypeError, tx.mchildByName, 'something') self.failUnlessRaises(AttributeError, t.mchildByName, 'doesntexist') # msubPlugs assert len(t.msubPlugs()) == 3 assert len(a.msubPlugs()) == 2 assert len(tx.msubPlugs()) == 0 # msetLocked tx.msetLocked(1) assert tx.isLocked() tx.msetLocked(0) assert not tx.isLocked() # msetKeyable tx.msetKeyable(0) assert not tx.isKeyable() tx.msetKeyable(1) assert tx.isKeyable() # msetCaching tx.msetCaching(0) #assert not tx.isCachingFlagSet() # for some reason, the caching cannot be changed here tx.msetCaching(1) assert tx.isCachingFlagSet() == 1 # msetChannelBox tx.msetChannelBox(0) assert not tx.isChannelBoxFlagSet() tx.msetChannelBox(1) assert tx.isChannelBoxFlagSet() == 1 # mconnectMultiToMulti # is tested elsewhere # connectTo self.failUnlessRaises(RuntimeError, persp.msg.mconnectTo, a[1], force=False) # already connected front.msg.mconnectTo(a[1], force=False) # already connected front.msg.mconnectTo(a[0], force=True) # force breaks connections persp.msg.mconnectTo(a[0]) # default is force # mconnectToArray # sufficiently tested ( -> st ) # mdisconnect # st # mdisconnectInput # st # mdisconnectOutputs # st # mdisconnectFrom # st # mdisconnectNode # st # mhaveConnection assert api.MPlug.mhaveConnection( front.msg, a[1]) and api.MPlug.mhaveConnection(a[1], front.msg) assert not api.MPlug.mhaveConnection( persp.msg, a[1]) and not api.MPlug.mhaveConnection( a[1], persp.msg) # misConnectedTo # st # moutputs assert len( front.msg.moutputs()) == 1 and front.msg.moutputs()[0] == a[1] assert len(a[0].moutputs()) == 0 # moutput # st # minputs assert len(a.minputs()) == 2 assert len(a[1].minputs()) == 1 # miterGraph # st # miterInputGraph # st # miterOutputGraph # st # minput # st # mconnections assert len(front.msg.mconnections()) == 2 assert len(a[1].mconnections()) == 2 # mdependencyInfo m = nt.Mesh() assert len(m.outMesh.maffected()) assert isinstance(m.outMesh.maffected()[0], api.MPlug) assert m.outMesh.maffected() == m.outMesh.mdependencyInfo(by=True) assert isinstance(m.inMesh.maffects(), list) # no affected items for some reason assert m.inMesh.maffects() == m.inMesh.mdependencyInfo(by=False) # mnextLogicalIndex|plug assert a.mnextLogicalIndex() == 2 assert a.mnextLogicalPlug().logicalIndex() # mwrappedAttribute assert isinstance(a.mwrappedAttribute(), nt.Attribute) # mwrappedNode assert isinstance(a.mwrappedNode(), nt.Node) # masData nt.PolyCube().output.mconnectTo(m.inMesh) # need data here assert isinstance(m.outMesh.masData(), nt.Data) # mfullyQualifiedName assert a.mfullyQualifiedName() != a.partialName()