Due to a miscommunication between Elsevier Press and the Python Software Foundation, the first printing of this title used an unauthorized modification of the trademarked Python logo. We apologize to the PSF for this, and they have been understanding of our in-press status; in the 2nd and subsequent printing of this title, we shall use a cover design that has been approved as non-dilutive by the Python Software Foundation.

Help make the world a better place and make a secure donation to the Python Software Foundation today!

 

Chapter 3

Writing Python Programs in Maya

Author

Seth Gibson

Project

Develop functions for a texture processing framework

Example Files

textures.py

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).


32 Responses to “Chapter 3”

  1. 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.

    • 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?

  2. 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

    • 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!

  3. Same page – missing ‘ ‘:
    arg_dict = {
    ‘prefix’:’grass_’,
    ‘texture_node’:tx1
    }
    # NameError: name ‘tx1’ is not defined #

  4. 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.

  5. 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. #

  6. 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 ?

    • 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)

  7. 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. . .

    • 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.

  8. 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

    • 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.

  9. 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

    • 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)

  10. 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

    • 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.

  11. 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!

  12. 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:)!

  13. please What is the meaning of this sentence
    status, texture = process_diffuse(name, out_dir)

  14. 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?

    • 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.

  15. 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 🙂

  16. 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

  17. import maya.cmds

    nodes = maya.cmds.ls(type=”transform*”)
    print(nodes)

    Does not works…Why?

    • 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’

  18. 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)

  19. 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?

Leave a Reply to Adam Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.