Search code examples
pythonsavemaya

Incremental Saves


I am trying to write up a script on incremental saves but there are a few hiccups that I am running into.

If the file name is "aaa.ma", I will get the following error - ValueError: invalid literal for int() with base 10: 'aaa' # and it does not happens if my file is named "aaa_0001"

And this happens if I wrote my code in this format: Link

As such, to rectify the above problem, I input in an if..else.. statement - Link, it seems to have resolved the issue on hand, but I was wondering if there is a better approach to this?

Any advice will be greatly appreciated!


Solution

  • Use regexes for better flexibility especially for file rename scripts like these.

    In your case, since you know that the expected filename format is "some_file_name_<increment_number>", you can use regexes to do the searching and matching for you. The reason we should do this is because people/users may are not machines, and may not stick to the exact naming conventions that our scripts expect. For example, the user may name the file aaa_01.ma or even aaa001.ma instead of aaa_0001 that your script currently expects. To build this flexibility into your script, you can use regexes. For your use case, you could do:

    # name = lastIncFile.partition(".")[0] # Use os.path.split instead
    name, ext = os.path.splitext(lastIncFile)
    
    import re
    
    match_object = re.search("([a-zA-Z]*)_*([0-9]*)$", name)
    # Here ([a-zA-Z]*) would be group(1) and would have "aaa" for ex.
    # and ([0-9]*) would be group(2) and would have "0001" for ex.
    # _* indicates that there may be an _, or not.
    # The $ indicates that ([0-9]*) would be the LAST part of the name.
    
    padding = 4  # Try and parameterize as many components as possible for easy maintenance 
    default_starting = 1
    verName = str(default_starting).zfill(padding)  # Default verName
    if match_object: # True if the version string was found
        name = match_object.group(1)
        version_component = match_object.group(2)
        if version_component:
            verName = str(int(version_component) + 1).zfill(padding)
    
    newFileName = "%s_%s.%s" % (name, verName, ext)
    incSaveFilePath = os.path.join(curFileDir, newFileName)
    

    Check out this nice tutorial on Python regexes to get an idea what is going on in the above block. Feel free to tweak, evolve and build the regex based on your use cases, tests and needs.

    Extra tips:

    Call cmds.file(renameToSave=True) at the beginning of the script. This will ensure that the file does not get saved over itself accidentally, and forces the script/user to rename the current file. Just a safety measure.

    If you want to go a little fancy with your regex expression and make them more readable, you could try doing this:

    match_object = re.search("(?P<name>[a-zA-Z]*)_*(?P<version>[0-9]*)$", name)
    name = match_object.group('name')
    version_component = match_object('version')
    

    Here we use the ?P<var_name>... syntax to assign a dict key name to the matching group. Makes for better readability when you access it - mo.group('version') is much more clearer than mo.group(2). Make sure to go through the official docs too.

    Save using Maya's commands. This will ensure Maya does all it's checks while and before saving:

    cmds.file(rename=incSaveFilePath)
    cmds.file(save=True)
    

    Update-2:

    If you want space to be checked here's an updated regex:

    match_object = re.search("(?P<name>[a-zA-Z]*)[_ ]*(?P<version>[0-9]*)$", name)
    

    Here [_ ]* will check for 0 - many occurrences of _ or (space). For more regex stuff, trying and learn on your own is the best way. Check out the links on this post.

    Hope this helps.