A simple pipeline

Hello, I’m trying to develop a little pipeline in Maya with Python.

The scope of this tool is very simple. Here the thing:

  • A modeler after has made his model in Maya runs the tool, a prompt window appears and into it he needs just to type the name of file.
  • At this point the file will be saved in two different folder on a server, just call them, update and backup, what fantasy, isn’t? :D:
    They are two copies of the same file, but in the update folder will be only one instance of the scene file without its History, while in the backup folder will be the file with that indexed name and its whole History.

My code seems to work properly, but there’s a problem with the indexes when I save a scene with different name or save the egual scene with same name at some point after.

Well, we suppose to have in the update folder a file named “Anto” and in the back folder we already have “Anto_1” and “Anto_2”, if I save another scene, said “Bobo”, it will be saved not with “Bobo_1” but, instead, with “Bobo_3” or if I do another saving of “Anto” after that I will have “Anto_4” an so on, I need to correct this behaviour.

Here my code, I’m doing my endeavours straight on my computer for trying to avoid other technical issues of different order.

import maya.cmds as cmds
import dircache

update_dir = "C:\Users\ASUS\Desktop\ProvaPython\\"
backup_dir = "C:\Users\ASUS\Desktop\ProvaPython1\\"
file_list = dircache.listdir(backup_dir)
unique_project_list = []
list_lenght = len(file_list) + 1
selected_item = 0
fname = ''
counter = 0
status = 'No'

#copy function definition
def copy_file(fname):
        cmds.file(rename = (update_dir + fname))
        cmds.delete(ch = True)
        cmds.file(save = True, type = 'mayaAscii')
        cmds.file(rename = (backup_dir + fname + "_" + str(list_lenght)))
        cmds.file(save = True, type = 'mayaAscii')
        cmds.confirmDialog(title='Saved', message='Save success', defaultButton='Close', cancelButton='Close')
        return

print("
")

while counter < len(file_list):
    if file_list[counter][0 : file_list[counter].index( '_' ) ] not in unique_project_list:
        unique_project_list.append (file_list[counter][0 : file_list[counter].index( '_' ) ])
    counter = counter + 1
    
while counter < len(unique_project_list):
    print(str(counter) + " = " + unique_project_list[counter])
    counter = counter + 1

selected_item = cmds.promptDialog(title='Choose an option', message='Enter displayed number:' + ' ' + str(len(unique_project_list)) + ' ' + 'for a new scene', button=['OK', 'Cancel'], defaultButton='OK', cancelButton='Cancel', dismissString='Cancel')
  
fname = raw_input('type a name file for backup
')
if fname not in unique_project_list:
        copy_file(fname)
elif fname in unique_project_list:
    status = cmds.confirmDialog(title='Confirm', message='WARNING!!:' + fname + ' ' + 'already exist.' + ' ' + 'Do you want to overwrite it?', button=['Yes','No'], defaultButton='Yes', cancelButton='No')
    if status == 'Yes':
        fname = raw_input('type a name file for backup
') #cmds.promptDialog(title='Save File', message='Type a name file for backup:', button=['Save', 'Cancel'], defaultButton='Save', cancelButton='Cancel', dismissString='Cancel')
        copy_file(fname)
    else:
        cmds.confirmDialog(title='Close', button=['Close'], defaultButton='Close', cancelButton='Close')

Now I was thinking to make a test into the function copy_file() I have defined, before to run those commands that save a file in the backup folder. Here the code of my idea:

import maya.cmds as cmds
import dircache

backup_dir = "C:\Users\ASUS\Desktop\ProvaPython1\\"
file_list = dircache.listdir(backup_dir)
fname = 'Anto'
unique_project_list = []
sub_backup_list = []
print file_list[0][0 : file_list[0].index( '_' ) ]

counter

while counter < len(file_list):
    if file_list[counter][0 : file_list[counter].index( '_' ) ] == fname:
        sub_backup_list.append (file_list[counter])
    print file_list[counter]
counter = counter + 1
    

print ("
")
print file_list
print sub_backup_list
print len(sub_backup_list)

So, from “file_list” I can set apart another list which I called “sub_backup_list” where it will be only the file instances with the current name stored in the “fname” variable and counting them by len(sub_backup_list), I want to use this information for generating an index, just the sublist’s lenght, and using it in the command inside copy_file(), as cmds.file(rename = (backup_dir + fname + “_” + str(list_lenght))) ,but str(list_lenght) returns me an integer value one unit back than len(sub_backup_list). How can I fix it?

Thanks a lot for any help or suggestions and I’m sorry again for grammar mistakes or improper language eventualy, as I already said the English is just a second language for me.

Gabriele.

a couple of things to think about:

  1. if you’re incremementing file names, use two or more digits: bobo_001, not bobo_1. That will make easier to sort.

  2. Do you need to ask the user for file names? Can’t you derive it from the maya file name? Users like not having to name things all the time

  3. You probably want to make sure your files always produce the same index in both folders. Instead of parsing the files in the folder, maybe you just want to store the last index in the file itself. That makes the code much shorter

This is a simple example the stores the index in the file. The weakness here is that if user tries to export the save the file again from an older version it will overwrite the files - you could easily add a check to warn the user before that happens.


import os
def save_and_save_backup():
     backup_dir = 'path/to/backup'
     update_dir = 'path/to/update'

     old_path, filename = os.path.split(cmds.file(q=True, sn=True))
     filename, extension = os.path.splitext(filename)
     #now old_path= 'path/to/file'
     # and filename = 'maya_filename', extension = '.ma'

     # get the old file index if it exists, then update it
     old_file_index = int(cmds.fileInfo ('file_version')) or -1
     new_file_index = old_file_index + 1
     cmds.fileInfo('file_version', new_file_index)

     # use python built in formatting to pad the numbers:
     indexed_name =  "%s_%03d.ma" % (filename, new_file_index)
    
     # save once as update
     update_file = os.path.join(update_dir, indexed_name)
     cmds.file (rename = update_file)
     cmds.file(save=true)
    
     # save again as backup
     backup_file =  os.path.join(backup_dir , indexed_name)
     cmds.delete(ch=True) 
     cmds.file (rename = backup_file)
     cmds.file(save=true)

     # do you want to get back to the original file?
     cmds..file(update_file, open=True)

Thanks a lot Theodox, for your reply and suggestions, I feel very interesting for the second one, at the end I have done it, I fixed the problem, and now It works right how I want that it works, sorry for the word’s play .
Here’s the code:

import maya.cmds as cmds
import dircache

update_dir = "C:\Users\ASUS\Desktop\ProvaPython\\"
backup_dir = "C:\Users\ASUS\Desktop\ProvaPython1\\"

file_update = dircache.listdir(update_dir)
file_list = dircache.listdir(backup_dir)
unique_project_list = []
sub_backup_list = []
                                          #list_lenght = len(sub_backup_list) + 1
selected_item = 0
fname = ''
status = 'No'

#copy function definition
def copy_file(fname):
        cmds.file(rename = (backup_dir + fname + "_" + str(len(sub_backup_list) + 1)))
        cmds.file(save = True, type = 'mayaAscii')
        cmds.file(rename = (update_dir + fname))
        cmds.delete(ch = True)
        cmds.file(save = True, type = 'mayaAscii')
        cmds.confirmDialog(title='Saved', message='Save success', defaultButton='Close', cancelButton='Close')
        print file_list
        print unique_project_list
        print sub_backup_list
        print len(sub_backup_list)
        print str(len(sub_backup_list) + 1)
        return

print("
")

fname = raw_input('type a name file for backup
')

counter = 0
while counter < len(file_list):
    if file_list[counter][0 : file_list[counter].index( '_' ) ] == fname:
        sub_backup_list.append (file_list[counter])
    counter = counter + 1

counter1 = 0
while counter1 < len(file_list):
    if file_list[counter1][0 : file_list[counter1].index( '_' ) ] not in unique_project_list:
        unique_project_list.append (file_list[counter1][0 : file_list[counter1].index( '_' ) ])
    counter1 = counter1 + 1

if fname not in unique_project_list:
        copy_file(fname)
elif fname in unique_project_list:
    status = cmds.confirmDialog(title='Confirm', message='WARNING!!:' + fname + ' ' + 'already exist.' + ' ' + 'Do you want to overwrite it?', button=['Yes','No'], defaultButton='Yes', cancelButton='No')
    if status == 'Yes':
        fname = raw_input('type a name file for backup
')
        copy_file(fname)
    else:
        cmds.confirmDialog(title='Close', button=['Close'], defaultButton='Close', cancelButton='Close')

If you notice the commented line, where I defined a variable “list_lenght = len(sub_backup_list) + 1”, I had to substitute str(list_lenght) with str(len(sub_backup_list) + 1) because the variable “list_lenght” didn’t seemed to update, don’t ask me why! :):

Now I consider it as the core, it does the basic functionality I was looking for.

Actually now I need for some directions to implementing a path to a server, I tried but I don’t know how can I do it exactly, I’m still looking, this is one of my first script in Python, any ideas?.

I would like to implement a differrent interface, with two tabs, first one will be the field where the user can type the name or as you suggested I’m gonna find a way for deriving it from Maya, more specifically from his own folder on his computer, but I would like to leave the possibility to change it anytime, and the other one will be called “Settings” where the administrator or any another guy in charge will be able to set the specifc path, I don’t know if it necessary to implement features as a controlling for the acces to the field only from authorized people, well details, I fear to open a Pandora’s box. :):

As last optimization, I read about as much more Pythonic solution to make use the dictionaries and trying to substitute them with the least rows of the code:

if fname not in unique_project_list:
        copy_file(fname)
elif fname in unique_project_list:
    status = cmds.confirmDialog(title='Confirm', message='WARNING!!:' + fname + ' ' + 'already exist.' + ' ' + 'Do you want to overwrite it?', button=['Yes','No'], defaultButton='Yes', cancelButton='No')
    if status == 'Yes':
        fname = raw_input('type a name file for backup
')
        copy_file(fname)
    else:
        cmds.confirmDialog(title='Close', button=['Close'], defaultButton='Close', cancelButton='Close')

What do you think?

Thanks a lot again.

Gabriele.

Server paths are fairly simple: you can either map the directory to a fake drive letter and use that, or use the network path directly (’\share\path o\file") Be especially careful about escaping the slashes ! “\\server\path\ o\file” works but neither “\\server\path\ o\file” nor “\\server\path\ o\file” does.

There is a larger issue with server credentials - you probably don’t want to store user names and passwords in a script. You can prompt the user for the info once and store it on their hard drive as a text file, that’s fairly secure since it never goes into your code or off their machine.

Thank you a lot, it works good now, bye.

Gabriele.