Chapter 3
Writing Python Programs in Maya
Author
Seth Gibson
Project
Develop functions for a texture processing framework
Example Files
Synopsis
This chapter introduces the fundamentals of creating Python programs by focusing on the development of functions. It presents a number of properties of functions including arguments and return values. The chapter also makes comparisons with MEL to introduce keywords and concepts for iteration, conditional statements, and exception handling when working with Maya commands. Readers will develop a basic texture processing framework throughout the chapter, which they could customize to use in their own work.
Resources
Python Programming Style Guide
Lambda Forms
Other Notes
None
Errata for the First Edition
On p. 105, the process_diffuse()
function contains a line reading shaders = maya.cmds.listConnections('%s.outColor'%'file1', destination=True,)
, which should instead read shaders = maya.cmds.listConnections('%s.outColor'%'file_node', destination=True)
.
Hi Seth,
You might already know this, but I’ll mention it, in case it hasn’t come to your attention. There is a tiny error, on page 92, step 12. Running the “process_all_textures(**kwargs)” function won’t return the results printed in the book, on page 93. Unless we remove the “_” from “prefix = concrete_”(bottom of page 92, 6th printed line up), or add an “elif”, to the process_all_textures() definition, similar to what I have written below:
elif pre[-1] == ‘_’:
pre = pre
I know it’s such a minor nitpick. The whole book is so solid so far that when I ran into it, I was rewriting the function multiple times to make sure that I hadn’t missed anything.
Lastly, I just to say, that this book has been an fantastic learning resource so far. Looking forward to working through the rest!
-Jeffrey M.
Jeffrey McCrea said this on June 15, 2012 at 11:30 pm |
Hi Jeffrey,
I just retested the example myself and still get the same results as those printed in the book. What results do you get?
Adam said this on June 16, 2012 at 12:22 pm |
Wow, excellent book! It would be useful to have all the code in the book to copy paste while testing, but typing practice is good too.
This is minor, but on P.73, step 20, I get different results. Where you state ‘my_file1’, I get ‘my_texture’:
def process_all_textures(**kwargs):
# Set defaults for dictionary entries, so def won’t choke if they are missing
pre = kwargs.setdefault(‘prefix’, ‘my_’)
texture = kwargs.setdefault(‘texture_node’) # Default value will be: None
print (‘%s%s’%(pre, texture))
# Calling with no keywords does nothing
process_all_textures() # my_None
# calling with an unhandled keyword produces no error:
process_all_textures(file_name=’default.jpg’) # my_None
# specifying the ‘texture_node’ key will process file1:
process_all_textures(texture_node= ‘texture’) # my_texture
Mitch said this on September 22, 2012 at 11:00 am |
Thanks for getting in touch, Mitch! I’m glad you’be been enjoying the book so far. The problem in this case is that this chapter is basically a big, run-on example. In this case, the variable
texture
was defined in step 6. Sorry for the confusion!Adam said this on September 22, 2012 at 12:05 pm |
Same page – missing ‘ ‘:
arg_dict = {
‘prefix’:’grass_’,
‘texture_node’:tx1
}
# NameError: name ‘tx1’ is not defined #
Mitch said this on September 22, 2012 at 11:15 am |
Likewise, in this case, the variable
tx1
was defined in step 16.Adam said this on September 22, 2012 at 12:06 pm |
Thanks for the quick response Adam!
My bad, I didn’t start following with code until P.72. Duh.
Thanks so much for writing this. I’ve been using Python in Maya for about 2 years – without a good understanding of what’s going on under the hood. The book is really expanding my understanding of the language and toolset.
Mitch said this on September 24, 2012 at 9:47 am |
Hi Adam:
I ran into another problem.
When working w/the code on P91-2, I get an error from line 17 of the def:
When we have:
newTextures = [‘nothing’,’persp’,cmds.shadingNode(‘file’,asTexture = 1)]
newTextures = process_all_textures3(prefix = ‘concrete_’, texture_nodes = newTextures)
Maya throws an error on line 17 when it tries to get nodeType on the string ‘nothing’:
cmds.nodeType(‘nothing’)# Error: No object matches name: nothing
Then if we take ‘nothing’ out of the list:
newTextures = [‘persp’,cmds.shadingNode(‘file’,asTexture = 1)]
Maya throws an error when it tries to rename the perspective camera:
# File “”, line 19, in process_all_textures3
# RuntimeError: Can’t rename a read only node. #
Mitch said this on September 25, 2012 at 6:13 pm |
Ignore my last post – I found an error in my function.
Sorry about that….
Mitch said this on September 25, 2012 at 6:18 pm |
Hi
I had an an error writing code from page 84 :
new_textures=process_all_textures(
texture_nodes=textures,
prefix=’dirt_’
)
print(new_textures)
# Error: AttributeError: ‘str’ object has no attribute ‘texture’ #
What could be wrong ?
hans said this on October 5, 2012 at 11:37 am |
Hi Hans,
I’d be willing to bet it’s a punctuation error in your method definition. In step 1, p. 83, I would wager you have a period instead of a comma in this part: ‘%s%s’%(pre, texture)
Adam said this on October 9, 2012 at 8:21 pm |
Hi guys. Fantastic book and incredibly helpful. I was just wondering if I could clarify something though? It’s more my understanding than your writing though. On page 72, after we declare the function as
process_all_textures(*args)
you say that “In this implementation, the function assumes that the data at position 0 corresponds to a prefix and that all further arguments in the slice are texture names.” And that the function requires one positional argument for the function to execute.
I was just wondering if you could clarify that a little? Surely as we have just used (*args) the function will just put everything into a tuple and see it all as the same thing? No matter what we put into the function, even the list underneath would work? Sorry for my muddled explanation. . .
Paddy said this on June 4, 2013 at 6:26 am |
Hi Paddy,
This particular code example is just a basic demonstration of variable-length argument lists, so unfortunately it’s a little vague and abstract since it doesn’t really get built on further. The main point with the section you cited was to emphasize that there must be at least one positional argument since index 0 is used explicitly in the method body, which itself was intended to be doing something like “print the prefix followed by a tuple of all of texture names.” Since there’s no actual functionality in there, it will of course execute as long as you pass in something.
Adam said this on June 27, 2013 at 2:07 pm |
Why is there so much white space at the side of the book? All the code has been crunched into a small column that rolls over to the next page and it is hard to know where the indents are supposed to be. I keep getting syntax errors and indent errors because of this. Is there a version of any of the scripts I can make comparison to as it is very frustrating having to keep going through it line by line to check for errors. I am using notepad++ and the script editor. Neither of which are very useful at pointing out where errors are.
Content is good, but presentation is proving to be the hold up with this learning curve
malcom armstrong said this on June 26, 2013 at 2:03 pm |
Hi Malcolm,
I’m sorry to hear you’ve been having issues. Unfortunately you’ve discovered one of the hardest problems to deal with when writing a book about Python. Final versions of any of the scripts which span multiple pages in the book should appear in the files repository on this site (http://maya-python.com/files/), which will hopefully help you follow along more easily.
Adam said this on June 27, 2013 at 1:09 pm |
Managed to get formatting right for the code on pages 100-102, but what is the result of the code up to the generation of this line?:
texture_nodes = maya.cmds.ls(type = ‘file’);
I tried running all the code from page 100 -the above line on page 102 in an empty scene, but nothing happened. I thought it was to return 3 empty lists if no nodes can be found. Confused
malcom armstrong said this on June 26, 2013 at 2:43 pm |
Hi Malcolm,
You may just not be seeing the results if you are executing in Maya’s Script Editor. Try testing it by doing something like this:
result = process_all_textures()
print(result)
Adam said this on June 27, 2013 at 2:25 pm |
hello,
i was wondering about this code.
def process_all_textures(**kwargs):
pre = kwargs.setefault(‘prefix’, ‘My_’)
texture= kwargs.setdefault(‘texture_node’)
## Here is the strange part
return maya.cmds.rename(texture, ‘%s%s’%(pre,texture))
## I run the function but i get an error.
process_all_textures(texture_node = texture)
NameError: Name ‘texture’ is not defined
if i run :
process_all_textures(texture_node = ‘war’)
RuntimeError: No object matches name
I don’t understand why running the ‘print’ works but as soon as i add the rename function and as to be return it goes all wrong :-)…this is Chapter 3, Page 75
thanks so much.
ps: great book can’t wait to go throught it all
olivier_katombe said this on June 16, 2014 at 9:15 pm |
Hi Olivier,
This is actually an editing miscalculation on my part. Basically, the examples in each chapter are written assuming you sit down and work through the whole thing in one session. In this case, the assumption is that you have a variable named
texture
in your __main__ namespace, whose value is the name of some file node in your scene (assigned in step 6 on p. 67). If you don’t have that variable defined, you’ll get a NameError when you try to access it. If you instead pass a string literal (e.g., ‘war’) instead of a variable, then the function will proceed, and the rename command will look for a node whose name matches that literal value.Adam said this on June 18, 2014 at 10:13 am |
Hi There,
So far the book is fantastic. But I could really do with some further explanation on using % within formatting strings.
For example:
def process_all_textures(texture_node, prefix):
print(‘Processed %s%s’%(prefix, texture_node));
I just don’t understand why they are being used and how?
I really hope someone can answer me as it’s really bugging me.
Thanks very much and hope to hear back!
Danny said this on August 29, 2014 at 3:57 pm |
Hi Danny! Glad the book is helping you so far. If you’re having trouble with the string formatting in the book, you may look at this section of the Python documentation: https://docs.python.org/2/library/stdtypes.html#string-formatting
That said, while we use the % operator throughout the text mostly due to space constraints of printing code, we strongly encourage use of str.format() instead. You can read about it here: https://docs.python.org/2/library/string.html#formatstrings
Happy programming!
Adam said this on August 30, 2014 at 8:03 pm |
Hi Seth, I’m having a hard time to understand a part of the function on page 97. Could you explain the part of:
if not(maya.cmds.ls(texture) and maya.cmds.nodeType(texture)==’file’):
I don’t understand the ls() command and the nodeType() command.
Thanks you very much and hope to hear back:)!
Marc-Alexandre said this on January 30, 2015 at 2:39 pm |
Hi there! Did you work through chapter 1? Some of these things are covered there. You should also check out the Python Command Reference (linked on chapter 1 page).
Adam said this on January 30, 2015 at 5:01 pm |
please What is the meaning of this sentence
status, texture = process_diffuse(name, out_dir)
may said this on January 7, 2017 at 4:13 am |
Seems this hasn’t been adressed yet:
In the “textures.py” supplied on this page there’s an error in line 18, it’s not
> print(‘Processing texture %s’%node)
but as printed correctly in the book
> print(‘Processing texture %s’%name)
And there’s another one in the same script, maybe: In line 89 it says
> ‘%s.outColor’%’file1’,
which produces an error. This is the same in the book so it’s probably just me doing something wrong, though I’d say this can’t possibly work because in line 74 it says
> if ‘_diff’ in file_node: return True”
I consequently renamed the texture-file in my scene (before launching the script, of course) to “file1_diff” and changed line 89 to
> ‘%s.outColor’%file_node,
This way everything works perfectly and the script compiles without errors.. what am I not getting?
Christoph said this on February 16, 2017 at 5:55 pm |
It looks like you in fact found a couple of mistakes. I’m surprised no one else noticed them yet! I have updated the file on the site and added a note in the errata section of this page.
Adam said this on February 17, 2017 at 4:05 pm |
Hi, I think I’ve found a small error on page 101, last line.
I’m not sure if my copy of the book is 1st or 2nd edition… I report it as well 🙂
The print command is missin a “s” for formatting the string.
print(‘Failed to process %’%name);
instead of
print(‘Failed to process %s’%name);
By the way, the textures.py file available for download is correct 🙂
Daniele said this on April 6, 2017 at 3:39 pm |
Hello I’m having a problem with the example of renaming texture files to have the prefix’dirt_’. It prints all 3 of the file nodes correctly but it only renames one file (‘file1’ to ‘dirt_file1’)… I was just wondering what I was doing wrong.
Here is the Process:
import maya.cmds;
def process_all_textures(**kwargs):
pre = kwargs.setdefault(‘prefix’, ‘my_’);
textures = kwargs.setdefault(‘texture_nodes’);
new_texture_names = [];
for texture in textures:
new_texture_names.append(
maya.cmds.rename(texture,’%s%s’%(pre, texture)));return new_texture_names;
#new scene with 3 file nodes
maya.cmds.file(new=True, f=True);
textures = [];
for i in range(3):
textures.append(
maya.cmds.shadingNode(‘file’, asTexture=True));
print(textures);
#pass to process_all_textures() and print
new_textures = process_all_textures(texture_nodes=textures, prefix=’dirt_’);
print(new_textures);
[u’file1′, u’file2′, u’file3′]
[u’dirt_file1′]
—–
Thank You
Morgan said this on September 7, 2017 at 11:30 am |
import maya.cmds
nodes = maya.cmds.ls(type=”transform*”)
print(nodes)
Does not works…Why?
Alexander Martinez said this on December 15, 2017 at 10:54 am |
Hi! Why do you have the asterisk inside the quotes? The problem here is that there is no node type ‘transform*’ but there is a node type ‘transform’
Adam said this on January 4, 2018 at 1:31 pm |
Hey, firstly great book. It’s really amazing how interesting this hole thing can be.
So I have a problem on page 92 and I can’t find a solution.
So the whole ‘process_all_textures’ script seems to work but at the end it doesn’t output ‘After: [u’concrete_file2’]’ it just prints the same as the page before it: ‘After: None’.
My full script is:
import maya.cmds
def process_all_textures(**kwargs):
pre = kwargs.setdefault(‘prefix’)
if(isinstance(pre, str) or isinstance(pre, unicode)):
if not pre[-1] == ‘_’:
pre += ‘_’
else:
pre = ”
textures = kwargs.setdefault(‘texture_nodes’)
new_texture_names = []
if (isinstance(textures, list) or isinstance(textures, tuple)):
for texture in textures:
if not (maya.cmds.ls(texture) and maya.cmds.nodeType(texture)==’file’):
continue
new_texture_names.append(maya.cmds.rename(texture,’%s%s’%(pre, texture)))
return new_texture_names
else:
maya.cmds.error(‘No texture nodes speficied’)
new_textures = [‘nothing’,’persp’,maya.cmds.shadingNode(‘file’, asTexture=True)]
print(‘Before: %s’%new_textures)
new_textures = process_all_textures(texture_nodes=new_textures, prefix=’concrete_’)
print(‘After: %s’%new_textures)
Farooq said this on November 29, 2018 at 2:52 am |
Hi
I’m having trouble with the changes to the code on pg 84-85
Here is what I have
import maya.cmds as cmds
def process_all_textures(**kwargs):
pre = kwargs.setdefault(‘prefix’,’my_’)
texture = kwargs.setdefault(‘texture_nodes’)
new_texture_names = []
if (isinstance(textures,list) or isinstance(textures, tuple)):
for texture in textures:
new_texture_names.append( cmds.rename(texture,’%s%s’%(pre,texture)))
return new_texture_names
else:
cmds.error(‘No texture nodes specified’)
cmds.file(new=True,force=True)
textures= []
for i in range(3):
textures.append(cmds.shadingNode(‘file’,asTexture=True))
print(textures)
new_textures [0]= process_all_textures( prefix =’mud_’)
print(new_textures)
I don’t get the error ‘No textures specified’ when I run this code
Any ideas?
Matt said this on December 6, 2018 at 1:09 pm |