Tuesday, May 4, 2010

A Character TD’s Random Thoughts

Learn about rigging, scripting, and problem solving from Ryan Trowbridge Home
About Me
Downloads
Contact
Feb 10The __main__ Module
Maya Python, Python No Comments »Did you ever wonder what Python does with all those variables and functions you write in the Maya script editor? No? Well I am going to tell you anyway. I recently refered to the Maya Script Editors Python global scope or main namespace as the main module to a friend. He said that I must have been tired and meant something else, but I didnt and here is why.

Type in and execute the following code into your script editor in a Maya Python tab:

print __name__

Which will print:

__main__

When you print __name__ in a module it will give you the namespace of the module itself. So why did printing __name__ work inside of the Script Editor? Now write a quick function and execute it in the Script Editor:

def test():
"""this function is a test"""
print "test"

Next type and execute the following line:

help(test)

#Result:
Help on function test in module __main__:

test()
testing

Continue reading »
Feb 04Maya Python UI Example
Maya Python 2 Comments »Its been awhile since I posted. Ive been creating a lot of Python UI’s of late. I have seen others struggle with creating their first UI. There are a few gotchas and the best way to set up a Python UI is different than setting it up with MEL.

A good way to setup your UI is to encapsulate the UI in a class including the functions you will use with the UI. You dont need all of your functions inside of the class. If you need to work with a function that is external to the class, you can use a partial function. When you set a button command to use a function it is best not to give it a string like you would in MEL. You should pass the functions directly to the command. You should not pass the functions as if you called them however like function() but by just giving it the name. If you need to pass an argument you need to use a partial function so the function does not get called until the user presses the UI item. You should note the UI button command happens to always pass one argument even if you dont pass anything to the function. If you pass your function one argument it will receive two, or if you pass two it will receive three. This is easily remedied by adding an extra unused argument.

I have several personal projects taking up my time right now so I am going to be brief on the how to and what does what part. The following example should help you get started. You can execute it from the script editor and start playing around with it.

import maya.cmds as cmds
from functools import partial

def myfunc(inst=None, thing=None, arg=None):
print 'arg: ', arg
print 'inst: ', inst
print 'thing: ', thing
data = cmds.button(inst.btnA, query=True, label=True)
print data

class ui():
def __init__(self, winName="winTheWindow"):
self.winTitle = "The Window"
self.winName = winName

def create(self):
if cmds.window(self.winName, exists=True):
cmds.deleteUI(self.winName)

cmds.window(self.winName, title=self.winTitle)
self.mainCol = cmds.columnLayout( adjustableColumn=True )
self.btnA = cmds.button( label='Press Me - External Func', c=partial(myfunc, self, 'say...') )
self.btnB = cmds.button( label='Press Me - Internal Func', c=partial(self.a, 'something...') )
self.btnC = cmds.button( label='Press Me - Internal Func No Args', c=self.b)
cmds.showWindow( self.winName )
cmds.window(self.winName, edit=True, widthHeight=[250,75])

def a(self, myarg=None, arg=None):
print 'myarg: ', myarg

def b(self, arg=None):
print 'buttons require an argument'
print 'the argument passed in will always be the last argument'

# create the window
inst = ui()
inst.create()

Have fun,
Ryan
May 18Q and A: Unicode and passing buttons commands
Maya Python No Comments »In response to an e-mail I received I wrote back this response. I figured I would post it.

So I was given this example and asked what the u charter was for in front of each string name returned in the list.


aList = cmds.ls(selection=True)
print aList

>>[u'pSphere1', u'pSphere2', u'pSphere3', u'pSphere4']
The long and the short of it is Unicode allows more characters than ASCII. ASCII can hold 256 values and Unicode can hold 65,536 values. This allows computers to support complex languages with many characters. If you want a more complex explanation go here:

http://www.amk.ca/python/howto/unicode

Getting back to the example. So the aList returns a list of string names using Python Unicode. Thats what the u stands for. It shouldnt bother you though nor affect anything.

So if you have two spheres in your scene and you run this in the script editor it will return u’pSphere2′ and u’pSphere1′ like this:


import maya.cmds as cmds

getlist = cmds.ls(sl=True)
print getlist
>>[u'pSphere2', u'pSphere1']
Continue reading »
Feb 13Python class operator overloading Part 2
Maya Python No Comments »I was curious if it was possible to overload the [] operators twice in a row to imitate a matrix while still using a single array. Someone gave me an example to go off of and here is a working example of how to make a flatMatrix class in python.

Try this in the Python script tab in Maya:

class SubItem:

def __init__(self, parent, idx):
self.parent = parent
self.idx = idx

def __repr__(self):
return repr(self.parent.data[self.idx])

def __setitem__(self, subIdx, item):
index = (self.idx * self.parent.col) + subIdx
self.parent.data[index] = item

def __getitem__(self, subIdx):
index = (self.idx * self.parent.col) + subIdx
return self.parent.data[index]

class flatMatrix:
def __init__(self, data):
self.data = data
self.col = 4

def __setitem__(self, key, item):
return SubItem(self, key, item)

def __getitem__(self, idx):
return SubItem(self, idx)

A = flatMatrix([0,1,2,3,
4,5,6,7,
8,9,10,11,
12,13,14,15])

print A[0][0]

A[0][0] = 50

print A[0][0]

I think its kind of cool. Not so sure I dig how complex it is to read though.
-RyanT
Feb 10Python class operator overloading
Maya Python No Comments »I have been converting a C++ plugin to Python and I came across some C++ code that I was unsure how to convert to Python. I needed to overload several operators like +, -, <<, and [] so how does one go about this? First thing which is always best is to find the python.org help docs.

http://www.python.org/doc/2.5.2/ref/numeric-types.html

Unfortunately they dont have any good examples so I went searching for more. And here is an example I compiled after my search concluded. The lambda function might seem a bit confusing at first but it simply defines two variables ( in this case ) then it runs an expression and at the end of it, it defines what those variables are. The map() function is even more simple. map() can run a function on a list. For example:

#map() example
def add_one(a):
return (a+1)

foo = [1,2,3,4]
foobar = map(add_one, foo)
print foobar
>>[2, 3, 4, 5]

lambda is special in that it is a function and operates on lists so its allowed to be inside of map()

#lambda example
foo = [1,2,3,4]
bar = [1,2,3,4]
foobar = lambda x, y: x + y, foo, bar
print foobar
( at 0x0000000017A9BEB8>, [1, 2, 3, 4], [1, 2, 3, 4])

And last here is the overload operators example:

Continue reading »
Feb 04Python urllib2 library module
Maya Python No Comments »I ran into this module and just thought it was cool so I thought I would mention it here. Python has a few modules for working with processing URL’s and using ftp. So you could create a tool that you share with the public and have it read a URL which would allow you to dynamically create start up messages or even tell the user that the tool has been updated. Ahhhh.. that could get scary.

import urllib2

# Open the URL for reading
urlFile = urllib2.urlopen('http://www.rtrowbridge.com/blog/about/')

# Get info abou the URL
urlFile.info()

# Read the URL source code
for line in urlFile:
try:
print line
except:
pass

Cheers,
-RyanT
Jan 12Create your own user preferences file using Maya Python
Maya Python No Comments »I saw this anydbm module and thought that it could be handy for storing certain user options. Maya already has a built in optionVar command that Python can use. There are a great many reasons to use optionVar’s. I just wanted to give an example of a built in Python library module that lets you create your own files like the optionVar file.

Note that this module creates binary files so I dont think they are as useful as creating your own asci file since asci is readable. As you can see in the example they are so easy to create and update I could see myself using them at some point.

import anydbm

# Create a new database file, use c - creating | r - reading | w - writing | n - newdatabase
db = anydbm.open('C://databasefile', 'w')

# Add new dictionary keys | values to the file
db['python'] = '1'
db['in'] = '2'
db['maya'] = '3'

# Print the data in the file
# As with all dictionarys in Python this will not print the values in order
# This is because Python is optimising how it stores the values so they can be accessed quickly
for k, v in db.iteritems():
print k, '\t', v

# This will auto overwrite the existing keys | values which makes it easy to update the file
db['python'] = 'is'
db['in'] = 'really'
db['maya'] = 'cool'

# The previous 1 2 3 values no longer exist and now maya will print the new values
for k, v in db.iteritems():
print k, '\t', v

db.close()

# Note: If no path is given files are stored as binary files in your Maya installation dirrectory
# C:\Program Files\Autodesk\Maya_version\bin\

Next on my list to show will be a Python Maya API utility node,
-RyanT
Dec 16Maya Python eval != MEL eval
Maya Python No Comments »I thought it worth a post on how eval works in Python. Somone posted a question on cgtalk about how they tried to use eval inside of a Python class and they received errors. They tried to test the code by executing the string in the script editor which worked. The problem is that eval is not for executing code it is for executing expressions. Here is some Python code as an example. Just run this in your Maya Python tab.

import maya.mel as mel
import maya.cmds as cmds

# Mel eval test
def meleval():
mel.eval('float $foo = 10;')

meleval()

# switch to the mel tab and type:
print $foo;

# this prints 10

# Switch back to the Python tab
# Now try python eval, which is for expressions
print eval( '1+1' )

# prints 2

# Try to get more complicated with eval though and this happens:
eval( 'foo = 10' )

# Error: ('invalid syntax', ('', 1, 5, 'foo = 10'))
# Traceback (most recent call last):
# File "", line 1, in
# SyntaxError: ('invalid syntax', ('', 1, 5, 'foo = 10')) #

# so what do you use?
def pyexec():
exec( 'foo = 10' )
print foo

pyexec()

# prints 10

# now try to print foo like you did with MEL eval
print foo

# Error: name 'foo' is not defined
# Traceback (most recent call last):
# File "", line 1, in
# NameError: name 'foo' is not defined #

# Now why is this?
# The exec executes in the scope that it is executed in
# You can get around this though:

def pyexecglobal():
exec( 'foo = 5' ) in globals()
exec( 'foob = 5' ) in locals()
print foo
print foob

pyexecglobal()

# Now try:
print foo

# success

print foob

# Error: name 'foob' is not defined
# Traceback (most recent call last):
# File "", line 1, in
# NameError: name 'foob' is not defined #

So exec is what you want.

-RyanT
Dec 16Maya Python print to output window
Maya Python No Comments »Just a brief example but say you are doing a task that locks up Maya and you want to get some feedback. Printing to the script editor is not helpful if you are batching files or you have a script that needs to do several tasks before finishing because Maya will not allow you to see the script editor until its finished.

Alternatively to print you can use the MEL trace command which prints to the output window of Maya. This is not a Python command technically and ends up being a bit messy when concatenating strings.

The last method shown I import the sys module and use __stdout__ which mimics C++ cout the most closely.

Another benefit is printing to the Output Window is much faster than printing to the script editor. Printing to the output window can help you debug certain types of scripts easier.

import sys
import maya.mel as mel
import maya.cmds as cmds

dagNodes = cmds.ls( dagObjects=True )

# print nodes in script editor, slow
print "List of nodes in the scene///////////////////////////////////////"
for dag in dagNodes:
print ('Dag Node: ' + dag)

# print nodes in output window, messy
mel.eval('trace "List of nodes in the scene///////////////////////////////////////";')
for dag in dagNodes:
mel.eval('trace (\"' + 'Dag Node: ' + dag + '\");')

# print nodes in output window, using Python sys module
sys.__stdout__.write( 'List of nodes in the scene///////////////////////////////////////\n' )
for dag in dagNodes:
sys.__stdout__.write( 'Dag Node: ' + dag + '\n')

Have fun,
-RyanT
Dec 03Maya Python Email Module
Maya Python 1 Comment »I was thinking today it would be handy to send an e-mail to myself when a tool was done. Guess what its fairly easy to do with Python in Maya and here is an example:

import smtplib
import email.Message

# Create a function to send an e-mail
def pyMail(user='', password='', serverURL=None, sender='', to='', subject='', text=''):

mailfailed = ''
try:
# The Message object helps with formating the e-mail for the server to read
message = email.Message.Message()
message['To'] = to
message['From'] = sender
message['Subject'] = subject
message.set_payload(text)

# Connect to the mailsever
# Also you can specify a specific port like this:
# mailServer = smtplib.SMTP(serverURL, 365)
print 'connecting...',
mailServer = smtplib.SMTP(serverURL)
mailServer.set_debuglevel(1)

# (Transport Layer Security) mode. All SMTP commands that follow will be encrypted.
print 'starting tls...',
try:
mailServer.starttls()
mailServer.ehlo(serverURL)
except: pass

# If you pass a user name and password it will be passed to the mail server
# Note if your server requires auth it will fail without
# If the server does not require auth it will fail if you pass it something
print 'logging in...',
if(user and password):
mailServer.login(user, password)

# It is a requirement to add '\n.\n' to the end of a message
print 'sending...',
mailfailed = mailServer.sendmail(sender, to, message.as_string())

print 'disconnecting...',
try:
mailServer.quit()
except: pass

print 'mail sent.'
except:
print 'Error in sending mail.',

if mailfailed:
print 'failed:', mailfailed # some recipients, but not all of them, failed

# Send an e-mail
pyMail( serverURL = 'mail.server.com',
sender = 'from@address.com',
to = 'to@address.com',
subject = 'hello',
text = 'world',
user = 'user',
password = 'password')

Not to hard ehh? And there is nothing wrong with you creating a python function like this and calling it with MEL if this is all you want from Python.

Happy coding,
-RyanT

No comments:

Post a Comment