Nov 27

Contents:
What import does
Temporarily add a new directory to import from
Permanently add a new directory to import from
Make import work like MEL source

What import does:

Since importing modules is important to understand and anyone first learning how to use Python will need to do this. I figured I would go over how to properly import python modules in Maya. I will go through examples of how to temporarily add a path to your sys.paths so that Python can find it and I will show how to add the path permanently. Last I give an example of a function I made so you can just pass it a path and it returns the module that was imported for you to work with.

First thing you learn with Python scripts is you can not use the menu item file/source script in the Maya script editor. I dont know why Maya shows you both .mel files and .py files since sourcing a .py file will only give you errors. Basically the point here is you dont source Python files. It wont work.

The way you import a python script is admittedly a bit more cumbersome than sourcing a MEL file. Python does not allow you to simply source a given path name to the file. This is not a Maya specific issue, but how python is designed.

Also importing a python script or module is not the same as sourcing in other ways. When you use import, Python checks to see if the module is loaded and if it is not it will read the module and create the data in a namespace. Python also compiles a .pyc file. So thats why you see extra files in your folder after importing a module. If the module has been changed after it was imported and you want to “source” that version then the correct code to use is:

reload( module )

When you import a python script you are to simply do this:

# import the filename into its own namespace with the same name
import module

# import the filename into its own namespace with a specified name
import module as newname

# Import all the definitions and variables of the module into the global namespace
# This defeats the purpose of Python making your code less modular so it should rarely be used
from module import *

# Reference specific variables and definitions into the global namespace from the module
from module import varA, varB

# Allows a variable to be passed to import and returns the module to a variable you specify
# The way this works is a bit odd since even if foo is imported you cant call foo.defname()
# you must in this case use the variable mod to call mod.defname()
mod = __import__( module )

It is not ok to type a file extension or a path name. You can not even use a variable with the correctly named string. You can however use __import__() if you want to give it a variable. I show an example of this later. When you import, Python will look for the script in a set of system paths that Python finds. Python looks in its standard module library paths and also includes the PYTHONPATH environment variable paths.

Maya also automatically adds these paths by default:

C:/Documents and Settings/Ryan Trowbridge/My Documents/maya/2008/prefs/scripts
C:/Documents and Settings/Ryan Trowbridge/My Documents/maya/2008/scripts/
C:/Documents and Settings/Ryan Trowbridge/My Documents/maya/scripts

It is important to note that Maya will not find any scripts in your /My Documents/maya/2008/scripts/ folder. Note that the path has an extra forward slash therefore Python finds nothing. I think the Maya programmers are to blame for that one. This might be fixed in Maya 2009. If you place your script in the /My Documents/maya/scripts path Python files will import fine. From reading on the boards some people seem to be confused about this and I think rightfully so. Thankfully you can fix this with the environment variable as I show later.

First lets look at what paths Python is looking for using the script editor. Open up your Maya script editor and in a python tab execute this code:

import sys

# sys.path is simply an array of system paths that gets created when you first start up maya
syspaths = sys.path

for path in syspaths:
	print path

Continue reading »

Nov 19

These are some examples of how storing data is much cleaner in Python. If you have not used an object oriented language before some of this might sound overly complex and scare you back to MEL. Just remember if you use Python in Maya you dont have to use all of its complexities but its nice to have them if you end up wanting to try other methods of coding.

So on to the good stuff. First I have a simplistic approach to using a python class to help store data from a user selected hierarchy. Second I have a more complex approach to doing the same thing.

To start you should open Maya and create some joints or nodes to create a hierarchy. These use the code examples to see what kind of data you can store and retrieve.

# Python Example V1
import maya.cmds as cmds

# Node list that will store the selected hiearchy
nodeList = []

class Node:

	# Initialize Node
	def __init__(self, node = None, parent=None, childs=None):

		# Create three public attributes inside Node
		# Note that it is easy to add new properties later
		self.node = node
		self.parent = parent
		self.childs = childs

# Function to recurse the selected nodes hiearchy
def recurseNodes( node ):

	print ('recursing node: ' + node )

	# Get the parent node and child nodes
	parent = cmds.listRelatives( node, parent = True )
	childs = cmds.listRelatives( node, children = True )

	# Maya returns an array - if listRelatives returns the parent remove it from the array
	if parent != None:
		parent = parent[0]

	# Create an instance of the "Node" object
	newNode = Node( node, parent, childs )

	# Add new node to nodeList
	nodeList.append( newNode )

	# Recurse children
	if( childs != None ):
		for child in childs:
			recurseNodes( child )

# Get selected node
sel = cmds.ls( sl=True )

# Iterate through selected nodes
for s in sel:
	recurseNodes( s )

# Print saved data in nodeList
# Note it is very simple to get the data you want
# and you are free to make the data much more complex
# for instance you could create a "Node" object for the parent
# and each child and store those in the node instance
# this way you could walk the hiearchy and get data quickly and easily
for node in nodeList:

	print '\n'

	print 'node name:'
	print node.node

	print 'parents name'
	print node.parent

	print 'childrens name(s)'
	print node.childs

Continue reading »

Nov 07

The last time I spoke about how to setup a MMatrix and use it with python. By default there are no vector classes that are part of python. This is not a problem since you can use the Maya API.

The MVector is actualy much easier to work with. You do not need to use the MScriptUtil class with MVector’s you can just simply give it a default value and start working with the new object. For example:

# Import the general maya API classes
import maya.OpenMaya as OpenMaya

# Create two MVectors
vectorA = OpenMaya.MVector(1.0, 1.0, 1.0)
vectorB = OpenMaya.MVector(2.0, 2.0, 2.0)

# Do some operations on them
vectorC = (vectorA + vectorB)
vectorD = (vectorA - vectorB)

# vectorC after adding vectorA and vectorB
print vectorC.x
print vectorC.y
print vectorC.z

# vectorD after subtracting vectorA and vectorB
print vectorD.x
print vectorD.y
print vectorD.z

# get the length of vectorC
print vectorC.length()

# normalize vectorC
vectorC.normalize()

# print the new normalized values
print vectorC.x
print vectorC.y
print vectorC.z

Note that if you want more information on the MVector class you can look it up in the Maya help documents.

Hopefully that helps!
-RyanT

Nov 05

I have talked to a few people that think there are no good ways to deal with Vectors or Matrices in Python. I wanted to present an example of how to use the Maya API to create an MMatrix class and introduce how the MScriptUtil class works to deal with API functions that use pointers.

# import mayas general API classes
import maya.OpenMaya as OpenMaya

# the MScriptUtil class is very important to python API users
# it allows python users to pass variable to an API function like it were a pointer

# Called by RTrunPointerExample()
def RTpointerExample( ptr ):

	print 'ptr changed using MScriptUtil';
	OpenMaya.MScriptUtil.setDouble ( ptr, 2.0 )

def RTrunPointerExample():

	# Define a MScriptUtil object
	fooba = OpenMaya.MScriptUtil()

	# Define the pointer type
	# only use the types that end in Ptr
	ptr = fooba.asDoublePtr()

	# Set a value
	OpenMaya.MScriptUtil.setDouble ( ptr, 1.0 )

	# Print that value
	print 'ptr = ', (OpenMaya.MScriptUtil.getDouble( ptr ))

	# Call a function passing it the pointer
	RTpointerExample( ptr )

	# Print the new value
	print 'ptr = ', (OpenMaya.MScriptUtil.getDouble( ptr ))

# execute this
RTrunPointerExample()
# which prints:
>> ptr =  1.0
>> ptr changed using MScriptUtil
>> ptr =  2.0

Continue reading »