Python


Intro

This page and subpages are some very basic mel-to-python conversion notes for beginners. Far more complete information on Python can be found at www.python.org, more involved python/Maya info at Python Wiki and mel wiki (in the 'Python' section)

See also: Principles of Good Programming (thanks to Zhen for the link..)

Python Path

(for PC anyways..)

first off, to use your python scripts in maya, in your local maya.env file, specify your python path.

PYTHONPATH = C:/MyDir/MyScripts;

you can have more than one python path in the .env file, if you set it up like so:

PYTHONPATH = firstPath;secondPath

helpful tips from Ryan Trowbridge

Where Did My PythonPath go?

import sys

for pythonPath in sys.path:

print pythonPath

(Jason Parks)

Over a Network

To put scripts in Master directory for multiple artists to source:

Or to call from script itself:

    • import sys

    • sys.path.append('/path/to/script/folder')

  • Not the full path to the script, just the directory it resides in. (arrantSquid)

sys.path and PYTHONPATH are two different things. If you don't want too

much (or any) per-user/machine deviance, you could try putting a root on

PYTHONPATH and doing all your site specific setup using a combination of

sitecustomize and userSetup, depending on how much segregation/detail you're

looking for.

(S. Gibson)

Functions & Arguments

How do I call an imported function from inside a button (for a GUI)?

First of all, make sure if the function you are calling doesn't have any arguments, you have (*arg) in the function's argument space:

# The proc

import maya.cmds as mc

import maya.mel as mel

def helloFoo(*args):

print 'hello foo'

mc.window()

mc.columnLayout()

mc.button(label='Hello',command=helloFoo)

mc.showWindow()

Then read Warp cat's entry on the Mel Wiki (thank you, WarpCat!):

Executing external functions via UI's authord in Python

which will take you to the Python Wiki for 'Functions' and 'Arguments'.

# code example from josh

import maya.mel as mm

import maya.cmds as mc

def printA():

print 'Hello world'

def printB():

print 'hello again'

def main():

win = mc.window()

mc.columnLayout()

mc.button(l='hi', c='printA(), printB()')

mc.showWindow(win)

main()

How do I call a MEL script from inside Python?

import maya.mel as mel

mel.eval('source \"amyScripts/ah_curvePresets.mel\";')

mel.eval('Jack \"bob\";')

ok, how about passing Python variables into a MEL script?

ie, I want to do something like this:

def pythonMod:

myVar = 'foo'

mel.eval ('someMelProc (myVar)')

How do I get my module to return a value?

in the way that global proc string foo() would return a string..

#returning values example

def hello(person):

if person == "amy":

return "hello there amy"

elif person == "bob":

return "hello there bob"

else:

return "i just don't know who you are anymore."

def sayHi():

hi = hello("bob")

print hi

sayHi()

Functions & Arguments--Python Style

At first glance (for the MEL user) a function looks like a procedure. But it is much more insidious.

(from the Python Wiki:)

There are four ways to assign arguments to a function definition.

arg : The function matches normal arguments by position, left to right, when passed in.

def foo(argA, argB):

print argA argB

arg = value : The function has a default value assigned to the keyword. But the user can override this with their own value.

def foo(argA= "happy", argB = "joy"):

print argA, argB

foo (argB = "happy", argA = "joy")

*args : Collects any number of unmatched positional arguments into a new tupple for processing. The variable name is arbitrary, it just needs to be preceded with a single asterix '*'.

def foo(*args):

print "your arguments are: ", args

foo ("happy", "joy")

**kwargs : Collects any number of unmatched keyword arguments into a new dictionary for processing. The variable name is arbitrary, it just needs to be preceded with double asterix '**'.

def foo(**kwargs):

print "made a dictionary: ", kwargs

for key in kwargs:

print key + " : " + kwargs[key]

foo(keyA = "valA", keyB = "valB", keyC = "muffins")

You can also pass an individual list into the function definition, and as long as the number is the same, when the function is called it can unpack the list/tuple

def foo(argA, argB, argC, argD):

print argA, argB, argC, argD

args = ("a", "b", "c", "d")

foo(*args)

# a b c d

Drag and drop callback

(in Maya 2011)

##-----------------------------------------------------

from maya.cmds import *

def onDrag( *a ):

print 'dragging', a

def onDrop( *a ):

print 'DROPPIN!', a

w=window()

f=formLayout()

b1=button( l='apples', p=f, w=60, h=20, dgc=onDrag, dpc=onDrop )

b2=button( l='bananas', p=f, w=60, h=20, dgc=onDrag, dpc=onDrop )

formLayout( f, e=True, ap=((b1, 'top', 10, 0), (b1, 'left', 10, 0),

(b2, 'top', 50, 0), (b2, 'left', 30, 0)) )

showWindow(w)

##-----------------------------------------------------

(H. McKenzie)

What is the Lambda?

Resources:

Python Wiki, 'Understanding Lambda'

Lambda Explanation

Lambda's are expressions that generate a new Function to be called later (similar to a function definition statement (def), but different). Since they are expressions, they can be used in places that Function definitions can not, such as within list and dictionaries.

from python wiki:

def makeFuncs():

#creates a blank array

ret = []

#with i starting at itself and incrementing four times, raise i

#to the power of x, and append the array

for i in range(4):

ret.append(lambda x, i = i: i ** x)

#return the new array

return ret

funcs = makeFuncs()

print funcs[0](2)

print funcs[1](2)

print funcs[2](2)

print funcs[3](2)

print funcs[4](2)#out of range

(still not exactly sure how it works..)

Modules

What is a Python module?

Python tells you! http://docs.python.org/tutorial/modules.html

Basically any script or library that you can access in Python with useful functions. Python comes with lots of them, like 're', 'textwrap', 'xml.dom.minidom', etc., and you can write your own as well. Python is neat!

Some standard Python modules and what they do

re

'Regular Expressions', can be used for string handling

textwrap

wraps text usefully somehow, there's a post on p.i.m. about it..

functools

The functools module is for higher-order functions: functions that act on or return other functions. In general, any callable object can be treated as a function for the purposes of this module.

  • ctypes

  • ctypes is essential. You might want to write a plugin in Python, and

  • find that the cost of converting data from C++ to Python and vice-

  • versa is acceptable (it isn't, always,) but the algorithm you want to

  • use is very expensive in CPython. ctypes lets you write bits of that

  • algorithm in C and easily call the C from Python.

  • Even when you can't afford CPython's ridiculously bad GC you can

  • prototype in Python and then replace the Python bit-by-bit with highly

  • optimized C using ctypes. At the end you will wind up with something

  • slightly (read insignificantly) faster than C-like C++ (no vtables,)

  • but more importantly you will have been able to test your algorithms

  • in Python, and keep them working at every step when translating them

  • to C. This is an extraordinarily valuable technique for plugin

  • writers.

  • (Tagore Smith)

  • cython

this is getting a bit off topic, but if you're into ctypes, you should check out cython. it's a python-like language that allows you to write hybrid python and c code. it can be used for about any conceivable purpose where python and c need to interact: c/c++ python bindings, fast compiled modules, exposing python libraries to c, even statically typing pure python code for speed. pretty slick and very easy to write.

to use c code within it, you must create special header files, as it cannot read c headers directly. this is a bit of a pain, but if anyone is interested in it, i can post what little i have so far for maya and people can add to it as they need it.

to give you an idea of what is possible with it, i'm using it to create python bindings to a c++ library which uses both the maya C++ API and arnold's C API. it gets really tricky because maya has its own bindings using swig, and arnold has its own using ctypes, which my bindings must be able to play nice with. so cython is the perfect common ground where i can write relatively simple code to convert back and forth between all these APIs and their various bindings.

(Chad Dombrova)

pickle

storing dictionaries of node settings

module parsing

I can vouch for Pickle as well. I use it for anything that needs saving and

loading.

Example of my implementation from my Animation Library Toole (PAIE):

Make a class to contain all information you need and a wrapper class that

handles file path, load, save, retrieval of information and deploying

information.

Fill op the dataContainer class with stuff and simply pickle the instance of

the class to a file. That'll save all the information plus the class data,

methods and whatnot so when you unpickle the file you'll instantly have the

whole class back in your wrapper where you can access all the data easily

without thinking of either parsers or sanity checks.. only issue is that

it's all serialized data so its difficult to edit manually in a text editor.

If you want to see the actual code you can get my file here:

https://www.creativecrash.com/maya/downloads/scripts-plugins/animation/c/paie

If anyone else is using it differently I'd be eager to hear their way as

well!

(J. Welner)

MRV

Well, I would also recommend taking a look at a very Maya specific

module called MRV. It is an extraordinary piece of work, that seems to

have been almost entirely done by one guy, who deserves some

recognition IMHO. It focuses on the API side of things, where Pymel is

a bit more focused on the MEL side of things. The two are

complementary in many ways, but they are also a bit incompatible which

is something that you have to bear in mind if you decide to use MRV.

MRV is actually pretty amazing. Dunno if you have written many API

tools/contexts for Maya, but one thing that is pretty annoying about

that is that it is very hard to get undo to work properly within a

Maya context. Hard enough that basically everyone who uses Maya knows

that you just can't reliably undo while using a tool. MRV has a whole

module/plugin that pretty much fixes this. I showed this to some co-

workers at our studio and they were amazed that I had undo working in

a context without doing _anything_ other than importing a Python

module and making a couple of calls. I'm working on a commercial plug-

in, and that would be a real selling-point for us, but...

The downside of MRV is that it patches a lot of stuff in Python for

Maya. Almost all of the patches are very reasonable. For instance,

once you have imported MRV MVectors and MPoints have a reasonable

print representation. Which is great. But I can't ship a commercial

plug-in that changes even the print behavior of those classes, because

you know that somewhere out there there is someone with a pipeline

that relies on how Python for Maya prints those classes.

MRV makes more important changes as well. In order to allow Pythonic

iteration MRV adds a __len__ method to a number of API classes,

including MPlug. This works OK with Python for Maya, but is

incompatible with PyMel, since PyMel checks the truth value of MPlugs

when printing Attributes, and throws an exception if they evaluate to

False. Since non-array MPlugs have length zero they evaluate as False.

I've patched this by adding a __nonzero__ method to MPlug, in our

software, but we clearly can't ship software that relies on things

like this, so we're going to have to take MRV out before we ship, and

re-implement the bits we use in a way that doesn't require modifying

classes at run-time.

None of the above should be taken as a criticism of Pymel or MRV. Both

are really solid pieces of work. We wanted to move fast at the

beginning of development, and MRV helped us do that (and Pymel is

really helping us now.) I knew, almost from the beginning, that we

would have to eventually remove the MRV dependency, so we limited our

use of it- we will have to give up the nice undo, but we can replace

everything else we used in a day or two of work. What we used really

sped us up, at a time when we needed it. Some of the above _could_ be

taken as a criticism of Autodesk's integration of Python into Maya.

Seems very slapdash to me, but I guess we all know that, and if that

weren't the case there would be no Pymel.

I had to say all that before strongly recommending MRV because it's

important to understand how it interacts with the standard Maya

environment before using it. There are a lot of cases where you you

just can't use it because it might step on other things. But there are

also a lot of cases where you can use it, particularly for in-house

tools run from the command-line. MRV is so useful in cases like that

that it would be folly to ignore its existence, IMHO. Sebastian Thiel

should be commended for building, almost single-handedly, such a great

library. Check it out.

(T. D. Smith)

Sphinx

documentation tool

PIL, Optparse

image processing

Importing multiple modules at once

use __import__ which lets you import using a string name to specify the module to import. You can then assign it into globals() for access:

Code:

module = __import__('math', globals(), locals()) reload(module) globals()['math'] = module

#test it

print math

the import command actually calls the __import__ function, so there's plenty of information on __import__ here: http://docs.python.org/library/functions.html

(Nathan Horne)

Or this--is so simple (from Pyrokinesis)

import foo, foo2

It would be alot better to import them in the scripts that

actually need them. We have a ton of python tools, but we do not

preimport them all dynamically. Its just too much overhead. What we

end up doing in our tool button commands is something like:

import myTool; myTool.run()

The only python script we preimport is an environment script.

I think I had something dynamic going on for our python plugin api

tools, but we stopped doing that.

(J. Israel)

Reload()

Be careful with this one--can use during testing, but if you use it during production it can mess up execution. Here below better explanations and methods from cgtalk:

usually, everybody just states which imports he needs for his module. PyEclipse does a good job adding import statements automatically when you use some class via autocomplete.

If the reload() part is the reason you're doing this... then I'd suggest not doing that.

Fiirst, adding "reload" to your module code causes a lot of problems with reusability. Imagine you'd want to import some 3rd party code and discover that upon import it will reload some of the code you need - this messes up quite a bit.

Solution is... Just write code as you'd normally do, without reloads. Create totally separate utility which reloads EVERYTHING you currently need. Here's where you can automate; i'd suggest loop through currently imported modules (sys.modules dictionary) and just deleting those entries that are your code - easily recognized if you put your code into one package.

Run that utility each time before your test code. *Plan* when you want it. Remember, if you reload twice in one execution, that may cause problems.

This way you can deliver reload-free code after testing, and have an automated reload while you're developing the code.

(uiron)

Agreed, my final code does not have reload calls in it, and as a practice I don't use reload Rarely if im testing in a live environment, and I need to reload to pick up my changes I might.

Though as Uiron mentioned I typically flush my environment, rather than reload.(and only when testing).

(pyrokinesis)

Classes

What is a class?

A mega-module--it basically contains a whole bunch of little modules that handle various bits of the functionality you would like.

General

What is the difference between a .py and .pyc file?

A .pyc file is compiled and unreadable in a text editor; a .py file is not. Maya automatically compiles your .py file if it is loaded/saved/executed from Maya.

As an important speed-up of the start-up time for short programs that use a lot of standard modules, if a file called spam.pyc exists in the directory where spam.py is found, this is assumed to contain an already-“byte-compiled” version of the module spam. The modification time of the version of spam.py used to create spam.pyc is recorded in spam.pyc, and the .pyc file is ignored if these don’t match.

Normally, you don’t need to do anything to create the spam.pyc file. Whenever spam.py is successfully compiled, an attempt is made to write the compiled version to spam.pyc. It is not an error if this attempt fails; if for any reason the file is not written completely, the resulting spam.pyc file will be recognized as invalid and thus ignored later. The contents of the spam.pyc file are platform independent, so a Python module directory can be shared by machines of different architectures. (python.org)

What is a '.py~' file?

Most recently saved version before current version?

What kind of variable is my variable??

Since Python doesn't require you to assign a type to your variables when you declare them, you can get into trouble. When you are assigning variables, check the 'Return Value' in Maya help to see what your command is expected to return.

For example, if you use 'joint' to create a joint, the Return Value is string, whereas if you use 'duplicate' to create a joint, it will return a string array. If you then try to call that string array as a string, Python will give you an error and cause you a lot of pain.

Loop Through A Bunch Of Procedures (like C++ Pointer Arguments)

https://codereview.stackexchange.com/questions/173739/invoking-functions-using-a-function-pointer-approach

PyQT

see GUI page

Can You teach me how to buil PyQt with VS for maya 2014 x64 ??

Marcus to the rescue! :)

I've documented the process of compiling PyQt for Windows

here<http://abstractfactory.io/blog/pyqt5-1-1-for-python-2-7/>,

but as the steps for Maya are a little special, you could also pull some

info from this here<http://abstractfactory.io/blog/building-pyzmq-for-python-2-7-msc-v-1600/>,

which goes through how to compile something else (PyZMQ) on Windows for

Maya. The steps are much the same.

In a nutshell, the differences between compiling for the vanilla Python

version on Windows versus compiling for Maya on Windows is that default

Python is compiled with Visual Studio 2010 whereas Maya uses a custom

Python compiled in VS2012. So you must use Maya's own python, mayapy.exe

for your compilation.

Best,

Marcus

I just remembered, I posted a compiled version not too long ago. If you'd

rather hop the compile, just grab this.

https://groups.google.com/forum/#!topic/python_inside_maya/yoxccAv3_VU

(M. Ottosson)

Resources

Python in Maya Google Group

Python Wiki

Python proper

Simple Python Examples

Maya Python For Games And Film - Adam Mechtley, Ryan Trowbridge, Seth Gibson

Python Scripting for Maya Artists (Chad Vernon)

MIT Course

Understanding Python (Google)

Google's Python Class

Do you have any suggestions for good resources for learning Python? Any other resources that you've found to be particularly useful?

JP: There are thousands of Python books and web pages. I stumble across new pages every day, usually ones specific to my immediate queries. I pretty much use Google as my main python docs. I find myself downloading or using new built-in modules/packages daily. So I'll just type in 'python xml example' for instance and tons of code and pages just pop up that people have put out there to help you out.

(Jason Parks from tech-artists.org)