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 »

Oct 25

I wanted to give another example that is even closer to how C++ overloading functions work. With python you can create functions that use keywords which are basically predefined variables. The good thing about this is a keyword does not have to have a variable passed to it because it already has a valid value. You can use this in a way to make a function work much like a maya command. For example these three lines are valid:

import maya.cmds as cmds

cmds.polySphere ( r=1 )
cmds.polySphere ( sx=10, sy=15, r=1 )
cmds.polySphere ( sy=15, r=1)

You could write your own maya command with Python API, which would be more complicated but completely possible. The good part of using the Python API to write a command is it includes other nice features that Maya does for you, but I wont get into that now. For now I will give an example how a basic function can imitate this. Example:

Continue reading »

Oct 22

So as one of my first posts I thought I would publish something on one of the reasons I like python over MEL. In C++ there something called function overloading. Which means you can create a function with the same name but different argument types and number of arguments. For example:

int foo( int varA )
{
    return (varA * 2);
}

double foo( double varA, int varB )
{
    return (varA * varB);
}

In the above C++ example you can pass foo an int which is valid or pass foo a double and an int which is valid.

So getting back to MEL and Python, MEL has strongly typed variables like C++ and no general way to overload functions. You could pass your procedure a string array and maybe have the first argument say what to do with that string array, but in the end your still passing and only can pass a string array to that variable.

In Python there is no way to create completely separate overload functions, but you can create a function that receive different types of variables and does completely separate actions based on what types it receives. For example:

Continue reading »