Deleting namespace the python way


#1

Hi all, I am trying to find some pythonic ways to delete the unnecessary/ empty namespaces. Attached is a screenshot in which I am trying to remove both the “v02” and “v03” as I had only wanted “camera01” namespace. As I have quite some maya scene files of similar if not the same issues, but the text of the namespace differs from file to file.

The following is the code that I have used:


curNS = cmds.namespaceInfo( lon=True )
defaults = ["UI", "shared", "camera01"]

diff = [item for item in curNS if item not in defaults]

for ns in diff:
	if cmds.namespace( exists=str(ns)):
		cmds.namespace(rm=str(ns))

Though I may be able to utilise namespace command, removeNamespace flag, I got stuck at this error:

# RuntimeError: The namespace 'v01' is not empty. # 

but I am sure that it is empty, nothing was listed in this namespace whatsoever

Any ideas?



#2

you’ll need to write a recursive function that starts at the bottom and empties namespaces one by one until you reach the top.


#3

So namespaces aren’t considered empty if they have a child namespace in them, even if that child is empty, and so on down the whole tree.

So pymel’s Namespace class actually has a remove method on it, this will aggressively remove all namespaces, and any nodes in those namespaces from the scene. You can use it like so:


import pymel.core as pm

defaults = ['UI', 'shared']
namespaces = (ns for ns in pm.namespaceInfo(lon=True) if ns not in defaults)
namespaces = (pm.Namespace(ns) for ns in namespaces)
for ns in namespaces:
    ns.remove()

If you’d rather stick to maya.cmds, and don’t want to have to come up with you’re own recursive method you can do something like this:


import maya.cmds as mc

defaults = ['UI', 'shared']

# Used as a sort key, this will sort namespaces by how many children they have.
def num_children(ns):
    return ns.count(':')

namespaces = [ns for ns in mc.namespaceInfo(lon=True, r=True) if ns not in defaults]
# We want to reverse the list, so that namespaces with more children are at the front of the list.
namespaces.sort(key=num_children, reverse=True)
for ns in namespaces:
    try:
        mc.namespace(rm=ns)
    except RuntimeError as e:
        # namespace isn't empty, so you might not want to kill it?
        pass

This one takes advantage of namespaces just being strings, and you can easily get the depth of a namespace tree by counting the number of ':'s in it. After that its as simple as wiping out the bottom most ones first as already mentioned.

@R.White: Your code rocks, despite the nested levels it may have! But in the maya.cmds code portion, there is no “sorted_ns” variable, it should probably the “namespaces” variable.

Good catch, was a leftover from doing:


sorted_ns = sorted(namespaces, key=num_children, reversed=True)

Which really gets you the same results.


#4

Thanks guys for the prompt reply! Never have I thought of using count and reversing the list - bottom up.

@R.White: Your code rocks, despite the nested levels it may have! But in the maya.cmds code portion, there is no “sorted_ns” variable, it should probably the “namespaces” variable.


#5

From the quick look, sorted_ns is the list you get from namespaces.sort(key=num_children, reverse=True)

sorted_ns = namespaces.sort(key=num_children, reverse=True)


#6

Thanks to this thread, and another that @R.White also responded to, I manage to do a thing!

    def doIt(self, args):
    ''' 
    Find all namespaces in scene and remove them.
    Except for default namespaces
    '''

    # Get a list of namespaces in the scene
    # recursive Flag seraches also children
    # internal Flag excludes default namespaces of Maya
    namespaces = []
    for ns in pymel.listNamespaces( recursive  =True, internal =False):
        namespaces.append(ns)
        print 'Namespace ' + ns + ' added to list.'

    # Reverse Iterate through the contents of the list to remove the deepest layers first
    for ns in reversed(namespaces):
        currentSpace = ns
        pymel.namespace(removeNamespace = ns, mergeNamespaceWithRoot = True)
        print currentSpace + ' has been merged with Root!'

    # Empty the List
    namespaces[:] = [] 

I am happy that I did this thing! And it works!