This small tutorial is to address a common problem that I have seen on
countless forums and email threads everywhere I go. This may have been
answered in a thread reply in the past but I can't recall ever seeing
it so I have decided to explicitly create a thread in hopes that it is
easier for users to search for in the future.
A common complaint among Maya users is how Maya masks details of
tracebacks. For most of us who work with Python extensively this is
increasingly more annoying as we depend on tracebacks during the
debugging process. I have seen people post little work around
techniques like copying and pasting the code from the external editor
to Maya's script editor and run it from there. This can be a work
around but it is cumbersome especially on large scripts.
Tracebacks can be exposed in Maya but you have to explicitly force
this to happen. To demonstrate this create a simple script in your
scripts directory called mayaTraceback.py and add the following:
import pymel.core as pm
def run():
for x in
pm.ls( type='transform'):
print x.longName()
# make and break some connections
x.sx >>
x.sy
x.sx >>
x.sz
x.sx //
x.sy
x.sx.disconnect()
# add and set a string array attribute with the
# history of this transform's shape
x.setAttr('newAt', x.getShape().histor(), force=1)
# get and set some attributes
x.rotate.set([1,1,1])
trans = x.translate.get
trans *= x.scale.get()
x.translate.set(trans)
Launch Maya and from within the script editor run the following:
import mayaTraceback
mayaTraceback.run()
You should see the following error:
# Error: AttributeError: nt.Camera(u'frontShape') has no attribute or
method named 'histor' #
This is what Maya users are used to seeing by now, but any experienced
Python user expects to see more. Now you could utilize some
engineering logic and simply look into the small chunk of code for a
'histor' attribute but just try to pretend this is a production script
and is roughly 5000+ lines of code. This is where we want something
more useful and descriptive.
Edit the script to also import the traceback module. Additionally edit
the run() function by abstracting out the 3 unique blocks within the
loop to their own functions. Now wrap the functions in a try/except.
Though Maya's original error message was limited it does tell use that
the exception was an AttributeError so we know the exception to catch.
In the except clause use the traceback shorthand for printing
exceptions.
import pymel.core as pm
import traceback
def run():
for x in
pm.ls( type='transform'):
print x.longName()
try:
_connections(x)
_historyAttr(x)
_setupAttrs(x)
except AttributeError:
traceback.print_exc()
def _connections(x):
'''make and break some connections'''
x.sx >>
x.sy
x.sx >>
x.sz
x.sx //
x.sy
x.sx.disconnect()
def _historyAttr(x):
'''add and set a string array attribute with the
history of this transform's shape
'''
x.setAttr('newAt', x.getShape().histor(), force=1)
def _setupAttrs(x):
'''get and set some attributes'''
x.rotate.set([1,1,1])
trans = x.translate.get
trans *= x.scale.get()
x.translate.set(trans)
Reload and rerun your script:
reload(mayaTraceback)
mayaTraceback.run()
Now we actually get a useful traceback that tells us that the error is
on line 53.
# Traceback (most recent call last):
# File "./mayaTraceback.py", line 31, in run
# _historyAttr(x)
# File "./mayaTraceback.py", line 53, in _historyAttr
# x.setAttr('newAt', x.getShape().histor(), force=1)
# File "/sww/tools/aw/maya2011/lib/python2.6/site-packages/pymel/
core/nodetypes.py", line 301, in __getattr__
# raise AttributeError,"%r has no attribute or method named '%s'"
% (self, attr)
# AttributeError: nt.Camera(u'topShape') has no attribute or method
named 'histor'
We also get tracebacks for each iteration of the loop. You could avoid
this by adding a 'break' statement after printing the traceback. Edit
the attribute to be 'history()' instead of 'histor()'. Reload the
script and try it again:
reload(mayaTraceback)
mayaTraceback.run()
You should see another error:
# Error: TypeError: NotImplementedType cannot be converted to Array or
any Array sub-class #
This is because I am cruel and left another error in the code, and a
slightly trickier one to debug by just glancing over the code. You may
or may not have found it in this small example but I have seen
colleagues spent days in larger libraries chasing errors like this
down.
Edit your run() function to now trap TypeErrors:
def run():
for x in
pm.ls( type='transform'):
print x.longName()
try:
_connections(x)
_historyAttr(x)
_setupAttrs(x)
except AttributeError:
traceback.print_exc()
break
except TypeError:
traceback.print_exc()
break
Your script editor should now print a useful exception.
# Traceback (most recent call last):
# File "./mayaTraceback.py", line 32, in run
# _setupAttrs(x)
# File "./mayaTraceback.py", line 60, in _setupAttrs
# trans *= x.scale.get()
# File "/sww/tools/aw/maya2011/lib/python2.6/site-packages/pymel/
core/datatypes.py", line 554, in __rmul__
# res = super(Vector, self).__rmul__(other)
# File "/sww/tools/aw/maya2011/lib/python2.6/site-packages/pymel/
util/arrays.py", line 6311, in __rmul__
# return Array.__rmul__(self, other)
# File "/sww/tools/aw/maya2011/lib/python2.6/site-packages/pymel/
util/arrays.py", line 4291, in __rmul__
# return self.__mul__(other)
# File "/sww/tools/aw/maya2011/lib/python2.6/site-packages/pymel/
core/datatypes.py", line 543, in __mul__
# return self.__class__._convert(res)
# File "/sww/tools/aw/maya2011/lib/python2.6/site-packages/pymel/
util/arrays.py", line 1544, in _convert
# raise TypeError, "%s cannot be converted to Array or any Array
sub-class" % (clsname(value))
# TypeError: NotImplementedType cannot be converted to Array or any
Array sub-class
I can tell here that the error occurred on line 60 within the
_setupAttrs() function. The real mistake is actually on line 59 which
should be 'trans = x.translate.get()' and not 'trans =
x.translate.get'. So even though the traceback was 1 line off from the
actual root of the problem it did, however, get me very close to the
root of the problem.
The code example is originally from the PyMEL home page (http://
code.google.com/p/pymel/) and was modified for this tutorial.