Maya Question Break all connections? command?

Hey guys sorry for all the rapid fire questions lately been trying to get a lot better with python and its been going pretty great thanks to all the wonderful people on this site. The question I have now is that i have a few connections on a camera and was wondering if there was a possible way for removing all the connections to an attribute.

What my current logic is this:


import maya.cmds as cmds
def removeAttr(*args):
	cameraSel = cmds.ls (sl=True)
	cameraShape = cameraSel[0]
	anysettingyouwant = (cameraShape + ".verticalFilmAperture") #vfa as an example
	list = cmds.listConnections(anysettingyouwant)
	print list
	if list != none:
	    for eachatribute in list:
	        cmds.disconnectAttr(anysettingyouwant, eachatribute)

#Really don't think this works. main problem is that there are multiple ways it could be set up such as
#Expressions
#Keyframe animations
#Constraints
#basic Connection editors	
#was wondering if there was a catch and remove all connections.

In addition if you guys could show me how to optimize my script that would be absolutely wonderful.
I’m starting to get better but i’m simply trying to get the script to work. However if i can learn to script cleaner and more *pythonically It would help me reach the next level.

thanks as always and much appreciated!

You have a couple basic issues here. The main ones involve the values that disconnectAttr requires and listConnections provides.

disconnectAttr syntax is:

cmds.disconnectAttr(sourceAttribute, destinationAttribute)

By default listConnections only returns the name of the node for each connection. So you’ll see something like this:

cmds.listConnections(attribute)
# ['pCube1']

That won’t work with disconnectAttr because it isn’t a full attribute. You can use the plugs flag to get listConnections to return the full attribute name

cmds.listConnections(attribute, plugs=True)
# ['pCube1.translateZ']

Getting better. The second requirement with disconnectAttr is that you have to specify the source attribute first. By default listConnections returns both source and destination attributes. You can restrict it to do one or the other, but that means you have to call it twice.

destinationAttrs = cmds.listConnections(attribute, plugs=True, source=False) or []
sourceAttrs = cmds.listConnections(attribute, plugs=True, destination=False) or []

If there are no connections, listConnections returns None. By adding the ‘or []’ to the end, if listConnections returns None, it will return an empty list [] instead. It just makes it easy when you go to loop through the result, since you’ll get an error if you try to loop through the None value

Now that you’ve separated the destination and source attributes, you can pass them to disconnectAttr in the correct order:

for destAttr in destinationAttrs:
    cmds.disconnectAttr(attribute, destAttr)
for srcAttr in sourceAttrs:
    cmds.disconnectAttr(srcAttr, attribute)

Ok that’s great you say, but what if I want to disconnect every connection to a node, and not just to a single attribute.

Well you can also call listConnections on a node. So:

cmds.listConnections(node)

will return all the connections to all attributes on that node. This introduces the wrinkle that you no longer know which attribute the connection is for, so you need to use the connections flag, which will cause it to return both ends of the connection. It returns this in a flat list: [thisNode, thatNode, thisNode, thatNode]. It ALWAYS returns the connection that goes to the node you are querying first. Meaning that regardless of whether it’s returning source, destination, or both types of connections, the connection to the node you are querying will come first. This is and important distinction because disconnectAttr requires the source attribute first, and listConnections doesn’t always return it that way.

To return all outgoing connections to a node:

outgoingPairs = cmds.listConnections(node, plug=True, connections=True, source=False)
# ['thisNode.attr1', 'thatNode.attr2', 'thisNode.translateZ', 'thatNode.rotateY']

Where every two items is a connection:
thisNode.attr1 -> thatNode.attr2
thisNode.translateZ -> thatNode.rotateY

I use zip to combine them into pairs. Look it up if you aren’t familiar with it:

outgoingPairs = zip(outgoingConns[::2], outgoingConns[1::2])
# This is easy to work with because that's the order disconnectAttr expects. So you can do:
for srcAttr, destAttr in outgoingPairs:
    cmds.disconnectAttr(srcAttr, destAttr)

However when you query the incoming connections it’s flipped:

cmds.listConnections(node, plugs=True, connections=True, destination=False)
# ['thisNode.translateY', 'thatNode.upValue', 'thisNode.forward', 'thatNode.translateZ']

Same idea that every two items is a connection, however the order is reversed, now it’s:
thatNode.upValue -> thisNode.translateY
thatNode.translateZ -> thisNode.forward

So you have to flip the list when you zip it:

incomingPairs = zip(inConns[1::2], inConns[::2])
for srcAttr, destAttr in incomingPairs:
    cmds.disconnectAttr(srcAttr, destAttr)

You can put this together in one big disconnectAll function:

def disconnectAll(node, source=True, destination=True):
    connectionPairs = []
    if source:
        conns = cmds.listConnections('pCube2', plugs=True, connections=True, destination=False)
        if conns:
            connectPairs.extend(zip(conns[1::2], conns[::2]))
    
    if destination:
        conns = cmds.listConnections('pCube2', plugs=True, connections=True, source=False)
        if conns:
            connectionPairs.extend(zip(conns[::2], conns[1::2]))
    
    for srcAttr, destAttr in connectionPairs:
        cmds.disconnectAttr(srcAttr, destAttr)

The real kicker is that this is how you do all that in PyMel:

pm.disconnectAttr(node)

I wrote this fast and with an assumption that you are very new to python in maya so please ask for additional details if something isn’t clear or I skipped over it (or tell me I’m being pedantic if you know parts of this). Also I wrote all this without testing it so there’s a chance I got the order or a flag wrong.

2 Likes

Also just some general stuff since I’m at work and don’t feel like actually working:

the ls command has a number of type-specific flags. Cameras is one of them. And beyond that you can specify a list of types using the type flag.

# Returns any selected camera shapes (not the camera transform!)
cmds.ls(sl=True, cameras=True)
# Does the same thing
cmds.ls(sl=True, type='camera')
# Type can also be a list which means you can return more than one type of selected item at once
cmds.ls(sl=True, type=['camera', 'nurbsCurve'])

You don’t need to use parentheses to combine strings. In fact you should use python’s string formatting instead of the + operator.

anysettingyouwant = '{0}.verticalFilmAperature'.format(cameraShape)

Don’t use list as an attribute name. It’s a built-in and you don’t want to override them as a general rule

print list
<type 'list'>

None, an empty string, and an empty list: they all have a boolean value of False and when doing True/False tests in python you can just use if/if not:

if object:
    # True
if not object:
    # False

So in your case (using your attribute name list):

if list:
    for eachattribute in list:
        ...
1 Like