scripted/pyMetaDataCmd.py

scripted/pyMetaDataCmd.py
1 import sys
2 import os
3 
4 import maya.api.OpenMaya as om
5 
6 """
7 To use, make sure that pyMetaDataCmd.py is in your MAYA_PLUG_IN_PATH
8 then do the following:
9 
10 Select a node
11 
12 import maya
13 maya.cmds.loadPlugin("pyMetaDataCmd.py")
14 maya.cmds.pyMetaData()
15 
16 There should now be an extra attribute on your node called:
17 ownerName
18 with your user name as its string value
19 """
20 
21 
22 def maya_useNewAPI():
23  """
24  The presence of this function tells Maya that the plugin produces, and
25  expects to be passed, objects created using Maya Python API 2.0.
26  """
27  pass
28 
29 
30 class PyMetaDataCmd(om.MPxCommand):
31  """
32  Plug-in command named 'pyMetaData'.
33 
34  pyMetaData adds a dynamic string attribute to selected dependency nodes.
35  Or, node names or a list of node names may be passed to the command.
36  Dynamic attributes on nodes can be used as meta-data.
37 
38  The force/f flag is used to specify the command will overwrite existing
39  dynamic string attributes of the same name.
40  False will prevent overwriting pre-existing attributes.
41  (default False)
42 
43  The value/v flag is used to specify a value to be set on the new attribute.
44  (default user name from USERNAME or USER envar)
45 
46  The name/n flag is used to specify a name string used to name the attribute.
47  (default 'userName')
48 
49  Undo/redo are supported.
50 
51  This command is written using Maya Python API 2.0.
52 
53  Example of usage, MEL:
54 
55  pyMetaData;
56  pyMetaData -f;
57  pyMetaData -force -name priorityLevel -value High;
58  pyMetaData -name health -v sick pSphere1 pSphere2;
59 
60  Example of usage, Python:
61 
62  maya.cmds.pyMetaData()
63  maya.cmds.pyMetaData(f=True)
64  maya.cmds.pyMetaData(force=True, name='priorityLevel', value='High')
65  maya.cmds.pyMetaData('pSphere1','pSphere2',name='health', v='sick')
66  maya.cmds.pyMetaData(['pSphere1','pSphere2'],name='health', v='sick')
67  """
68 
69  # Variables to be used in Class
70  #
71  cmdName = 'pyMetaData'
72 
73  nameFlag = '-n'
74  nameFlagLong = '-name'
75 
76  forceFlag = '-f'
77  forceFlagLong = '-force'
78 
79  valueFlag = '-v'
80  valueFlagLong= '-value'
81 
82 
83  def __init__(self):
84  om.MPxCommand.__init__(self)
85 
86  @staticmethod
87  def creator():
88  return PyMetaDataCmd()
89 
90  @staticmethod
91  def createSyntax():
92  """
93  Using kSelectionList in setObjectType
94  and calling useSelectionAsDefault(True),
95  allows us to use either a command line list of nodes,
96  or use the active selection list if no node names are specified.
97 
98  The force/f flag is defined as requiring no arguments.
99  By not specifying any arguments for the flag when we define it,
100  the flag will not require any arguments when used in MEL,
101  it will still require a value of 'True' or 'False' when used in Python.
102  """
103  syntax = om.MSyntax()
104  syntax.setObjectType(om.MSyntax.kSelectionList)
105  syntax.useSelectionAsDefault(True)
106  syntax.addFlag(PyMetaDataCmd.forceFlag, PyMetaDataCmd.forceFlagLong)
107  syntax.addFlag(PyMetaDataCmd.nameFlag, PyMetaDataCmd.nameFlagLong, om.MSyntax.kString)
108  syntax.addFlag(PyMetaDataCmd.valueFlag, PyMetaDataCmd.valueFlagLong, om.MSyntax.kString)
109  return syntax
110 
111  def doIt(self, args):
112  # Use an MArgDatabase to Parse our command
113  #
114  try:
115  argdb = om.MArgDatabase(self.syntax(), args)
116  except RuntimeError:
117  om.MGlobal.displayError('Error while parsing arguments:\n#\t# If passing in list of nodes, also check that node names exist in scene.')
118  raise
119 
120  # SELECTION or LIST of Node Names
121  #
122  selList = argdb.getObjectList()
123 
124  # FORCE
125  #
126  force = argdb.isFlagSet(PyMetaDataCmd.forceFlag)
127 
128  # NAME
129  #
130  if argdb.isFlagSet(PyMetaDataCmd.nameFlag):
131  name = argdb.flagArgumentString(PyMetaDataCmd.nameFlag, 0)
132  else:
133  name = 'ownerName'
134 
135  # VALUE
136  #
137  if argdb.isFlagSet(PyMetaDataCmd.valueFlag):
138  value = argdb.flagArgumentString(PyMetaDataCmd.valueFlag, 0)
139  else:
140  if os.environ.has_key('USERNAME'):
141  value = os.environ['USERNAME']
142  elif os.environ.has_key('USER'):
143  value = os.environ['USER']
144  else:
145  value = 'USERNAME'
146 
147 
148 
149  # Use an MDGModifier so we can undo this work
150  #
151  self.dgmod = om.MDGModifier()
152 
153  # Define a function to do most of the work
154  #
155  def addMetaData(dependNode, fnDN):
156  # Check to see if the attribute already exists on the node
157  #
158  if fnDN.hasAttribute(name):
159  if force:
160  plug = om.MPlug(dependNode, fnDN.attribute(name))
161  self.dgmod.newPlugValueString(plug, value)
162  self.dgmod.doIt()
163  else:
164  print ('passing over "' + fnDN.name()+ '": force flag not set to True')
165  else:
166  # Create a new attribute
167  #
168  fnAttr = om.MFnTypedAttribute()
169  newAttr = fnAttr.create(name, name, om.MFnData.kString)
170 
171  # Now add the new attribute to the current dependency node,
172  # using dgmod to facilitate undo
173  #
174  self.dgmod.addAttribute(dependNode, newAttr)
175  self.dgmod.doIt()
176 
177  # Create a plug to set and retrieve value off the node.
178  #
179  plug = om.MPlug(dependNode, newAttr)
180 
181  # Set the value for the plug, using dgmod to facilitate undo
182  #
183  self.dgmod.newPlugValueString(plug, value)
184  self.dgmod.doIt()
185 
186 
187  # Iterate over all dependency nodes in list
188  # add the meta-data attribute if it is not already there
189  #
190  for i in range(selList.length()):
191  # Get the dependency node and create
192  # a function set for it
193  #
194  try:
195  dependNode = selList.getDependNode(i)
196  fnDN = om.MFnDependencyNode(dependNode)
197  except RuntimeError:
198  om.MGlobal.displayWarning('item %d is not a depend node'%i)
199  continue
200  addMetaData(dependNode, fnDN)
201 
202  def redoIt(self):
203  self.dgmod.doIt()
204 
205  def undoIt(self):
206  self.dgmod.undoIt()
207 
208  def isUndoable(self):
209  return True
210 
211 def initializePlugin(plugin):
212  pluginFn = om.MFnPlugin(plugin)
213  pluginFn.registerCommand(
214  PyMetaDataCmd.cmdName, PyMetaDataCmd.creator, PyMetaDataCmd.createSyntax
215  )
216 
217 def uninitializePlugin(plugin):
218  pluginFn = om.MFnPlugin(plugin)
219  pluginFn.deregisterCommand(PyMetaDataCmd.cmdName)
220 
221 #-
222 # ==========================================================================
223 # Copyright (C) 2011 Autodesk, Inc. and/or its licensors. All
224 # rights reserved.
225 #
226 # The coded instructions, statements, computer programs, and/or related
227 # material (collectively the "Data") in these files contain unpublished
228 # information proprietary to Autodesk, Inc. ("Autodesk") and/or its
229 # licensors, which is protected by U.S. and Canadian federal copyright
230 # law and by international treaties.
231 #
232 # The Data is provided for use exclusively by You. You have the right
233 # to use, modify, and incorporate this Data into other products for
234 # purposes authorized by the Autodesk software license agreement,
235 # without fee.
236 #
237 # The copyright notices in the Software and this entire statement,
238 # including the above license grant, this restriction and the
239 # following disclaimer, must be included in all copies of the
240 # Software, in whole or in part, and all derivative works of
241 # the Software, unless such copies or derivative works are solely
242 # in the form of machine-executable object code generated by a
243 # source language processor.
244 #
245 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
246 # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
247 # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
248 # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
249 # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
250 # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
251 # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
252 # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
253 # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
254 # OR PROBABILITY OF SUCH DAMAGES.
255 #
256 # ==========================================================================
257 #+