def getMetaData(node, className=None): """ Return meta data from a node. If `className` is given returns only meta data for that meta class type. Args: node: A PyMel node or string node name className: A string name of the meta class type. Returns: A dict or python object representing the stored meta data """ mfnnode = utils.getMFnDependencyNode(node) try: plug = mfnnode.findPlug(METADATA_ATTR) datastr = plug.asString() except RuntimeError: return else: refNode = None if pm.cmds.referenceQuery(str(node), isNodeReferenced=True): refNode = pm.cmds.referenceQuery(str(node), rfn=True) data = decodeMetaData(datastr, refNode) if className is not None: return data.get(className, None) else: return data
def setAllMetaData(node, data, undoable=True): """ Set all meta data on a node. This is faster because the existing data on the node is not retrieved first and then modified. The data must be first indexed by strings that are valid meta class names, otherwise errors may occur when retrieving it later. New meta class attributes will be added automatically, but existing meta class attributes will not be removed. If old meta class attributes on this node will no longer be applicable, they should be removed with removeAllData first. Args: node (PyNode or str): The node on which to set data data (dict): The data to serialize and store on the node undoable (bool): When True, the operation will be undoable """ mfnnode = utils.getMFnDependencyNode(node) plug = _getOrCreateMetaDataPlug(mfnnode, undoable) # add class attributes if data: for className in data.keys(): _addMetaClassAttr(mfnnode, className, undoable) # set meta data newValue = encodeMetaData(data) if undoable: cmds.setAttr(plug.name(), newValue, type='string') else: plug.setString(newValue)
def setMetaData(node, className, data, undoable=True, replace=False): """ Set the meta data for the a meta class type on a node. The className must be a valid attribute name. Args: node (PyNode or str): The node on which to set data className (str): The data's meta class type name data (dict): The data to serialize and store on the node undoable (bool): When True, the operation will be undoable replace (bool): When True, will replace all data on the node with the new meta data. This uses setAllMetaData and can be much faster with large data sets. """ if replace: setAllMetaData(node, {className: data}, undoable) return mfnnode = utils.getMFnDependencyNode(node) plug = _getOrCreateMetaDataPlug(mfnnode, undoable) _addMetaClassAttr(mfnnode, className, undoable) # update meta data refNode = None if cmds.referenceQuery(str(node), isNodeReferenced=True): refNode = cmds.referenceQuery(str(node), rfn=True) fullData = decodeMetaData(plug.asString(), refNode) fullData[className] = data newValue = encodeMetaData(fullData) if undoable: cmds.setAttr(plug.name(), newValue, type='string') else: plug.setString(newValue)
def removeMetaData(node, className=None): """ Remove meta data from a node. If no `className` is given then all meta data is removed. Args: node: A PyMel node or string node name className: A string name of the meta class type. Returns: True if node is fully clean of relevant meta data. """ if not isMetaNode(node): return True mfnnode = utils.getMFnDependencyNode(node) if className is not None: # remove meta data for the given class only # make sure data attribute is unlocked dataPlug = _getMetaDataPlug(mfnnode) if dataPlug and dataPlug.isLocked(): return False # make sure class attribute is unlocked classPlug = _getMetaClassPlug(mfnnode, className) if classPlug and classPlug.isLocked(): return False data = decodeMetaData(plug.asString()) if className in data: del data[className] plug.setString(encodeMetaData(data)) else: # remove all meta data from the node # make sure data attribute is unlocked dataPlug = _getMetaDataPlug(mfnnode) if dataPlug and dataPlug.isLocked(): return False # make sure all class attributes are unlocked classPlugs = [ _getMetaClassPlug(mfnnode, c) for c in getMetaClasses(node) ] for cp in classPlugs: if cp and cp.isLocked(): return False # remove all attributes if dataPlug: mfnnode.removeAttribute(dataPlug.attribute()) for cp in classPlugs: if cp: mfnnode.removeAttribute(cp.attribute()) return True
def setMetaData(node, className, data, undoable=True): """ Set the meta data for the a meta class type on a node. Args: node: A PyMel node or string node name className: A string name of the meta class type. data: A python object to serialize and store as meta data undoable: A bool, when True the change will be undoable """ # get meta data plug mfnnode = utils.getMFnDependencyNode(node) try: plug = mfnnode.findPlug(METADATA_ATTR) except: if undoable: cmds.addAttr(mfnnode.name(), ln=METADATA_ATTR, dt='string') else: mfnattr = api.MFnTypedAttribute() attr = mfnattr.create(METADATA_ATTR, METADATA_ATTR, api.MFnData.kString) mfnnode.addAttribute(attr) plug = mfnnode.findPlug(METADATA_ATTR) # ensure node has meta class type attribute if not VALID_CLASSATTR.match(className): raise ValueError('Invalid meta class name: ' + className) classAttr = METACLASS_ATTR_PREFIX + className try: mfnnode.attribute(classAttr) except RuntimeError: if undoable: cmds.addAttr(mfnnode.name(), ln=classAttr, at='short') else: mfnattr = api.MFnNumericAttribute() attr = mfnattr.create(classAttr, classAttr, api.MFnNumericData.kShort) mfnnode.addAttribute(attr) # update meta data refNode = None if cmds.referenceQuery(str(node), isNodeReferenced=True): refNode = cmds.referenceQuery(str(node), rfn=True) fullData = decodeMetaData(plug.asString(), refNode) fullData[className] = data newValue = encodeMetaData(fullData) if undoable: cmds.setAttr(plug.name(), newValue, type='string') else: plug.setString(newValue)
def setMetaData(node, className, data): """ Set the meta data for the a meta class type on a node. Args: node: A PyMel node or string node name className: A string name of the meta class type. data: A python object to serialize and store as meta data """ # get meta data plug mfnnode = utils.getMFnDependencyNode(node) try: plug = mfnnode.findPlug(METADATA_ATTR) except: mfnattr = api.MFnTypedAttribute() attr = mfnattr.create(METADATA_ATTR, METADATA_ATTR, api.MFnData.kString) mfnnode.addAttribute(attr) plug = mfnnode.findPlug(METADATA_ATTR) # ensure node has meta class type attribute if not VALID_CLASSATTR.match(className): raise ValueError('Invalid meta class name: ' + className) classAttr = METACLASS_ATTR_PREFIX + className try: mfnnode.attribute(classAttr) except RuntimeError: mfnattr = api.MFnNumericAttribute() attr = mfnattr.create(classAttr, classAttr, api.MFnNumericData.kInt) mfnnode.addAttribute(attr) # update meta data refNode = None if pm.cmds.referenceQuery(str(node), isNodeReferenced=True): refNode = pm.cmds.referenceQuery(str(node), rfn=True) fullData = decodeMetaData(plug.asString(), refNode) fullData[className] = data plug.setString(encodeMetaData(fullData))
def removeMetaData(node, className=None, undoable=True): """ Remove meta data from a node. If no `className` is given then all meta data is removed. Args: node: A PyMel node or string node name className: A string name of the meta class type. undoable: A bool, when True the change will be undoable Returns: True if node is fully clean of relevant meta data. """ if not isMetaNode(node): return True mfnnode = utils.getMFnDependencyNode(node) # this may become true if we find there are no # classes left after removing one removeAllData = False if className is not None: # remove meta data for the given class only # make sure class attribute is unlocked classPlug = _getMetaClassPlug(mfnnode, className) if classPlug and classPlug.isLocked(): return False # make sure data attribute is unlocked dataPlug = _getMetaDataPlug(mfnnode) if dataPlug and dataPlug.isLocked(): return False # remove class attribute if classPlug: if undoable: cmds.deleteAttr(classPlug.name()) else: mfnnode.removeAttribute(classPlug.attribute()) # remove class data data = decodeMetaData(dataPlug.asString()) if className in data: del data[className] newValue = encodeMetaData(data) if undoable: cmds.setAttr(dataPlug.name(), newValue, type='string') else: dataPlug.setString(newValue) # check if any classes left if len(data) == 0: removeAllData = True else: # no className was given removeAllData = True if removeAllData: # remove all meta data from the node # make sure all class attributes are unlocked classPlugs = [ _getMetaClassPlug(mfnnode, c) for c in getMetaClasses(node) ] for cp in classPlugs: if cp and cp.isLocked(): return False # make sure data attribute is unlocked dataPlug = _getMetaDataPlug(mfnnode) if dataPlug and dataPlug.isLocked(): return False # remove class attributes for classPlug in classPlugs: if classPlug: if undoable: cmds.deleteAttr(classPlug.name()) else: mfnnode.removeAttribute(classPlug.attribute()) # remove data attribute if dataPlug: if undoable: cmds.deleteAttr(dataPlug.name()) else: mfnnode.removeAttribute(dataPlug.attribute()) return True