[Python] Search and replace lines in an ASCII .ma file



Hi there,
I am developping an automated tool which will help my production team send maya files and attached textures to another studio. Everything must be done without any maya install on the user computer, so pure Python only.

After copying the texture files from LOCALproject/sourceimages/assetName to FTPproject/sourceimages/assetName, I need to change the file paths directly into the ASCII .ma file.
I’m stuck there, as I don’t find any way to only change the lines I want to change. For now, my solution is way too long, as I need to copy more than 1M line from the .ma to a new clean ASCII file, with the filePaths changed:

Simplified script to show my solution:

maASCIIFile_read = open(sceneToCopy, 'r')
maASCIIFile_write = open(sceneToSend, 'w+')
maASCIIFile_read.seek(0) # back to first line
ASCIIFileLine_l = maASCIIFile_read.readlines()
for line in ASCIIFileLine_l:
    if '/sourceimages/' in line:
         i = ASCIIFileLine_l.index(line)
         correctedLine = line.replace(mapPath, relativeMapPath)
         ASCIIFileLine_l[i] = correctedLine

While this works, it is way too long. I need a fast solution, as I want to be able to handle lots of files.
What would be the best way to do that?



Testing this on a 800k size maya file with 29 path references takes ~2 seconds:

import re

# – Define our search and replace
replace_this = r’c:/test/my_local_path/sourceimages’
with_this = r’e:/other/some_other_project/sourceimages’

# – Use a regex to do the substitution as that is very quick
regex = re.compile(replace_this)

# – Get our input and output files
filepath = r’C:\dir\file_test.ma’
output_file = r’c:\dir\updated.ma’

# – Write the file with the replacement values
with open(filepath, ‘r’) as read_stream:
with open(output_file, ‘w’) as write_stream:
write_stream.write(regex.sub(with_this, read_stream.read()))


I don’t know if this is the case, but if you still have slow performance, you may be dealing with networked drive issues. If this is the case, it may be better to copy the file locally, process it by outputting to another local file, then save the processed local file to it’s eventual destination.


My guess is Ben needs to grab the texture file paths so he knows what to copy, but he left that code out of his example. Still doing things one line at a time like you are doing should be faster than building up an array of the entire file.


A longer term solution here is to define an environment variable that acts as the root of your asset storage.

So that c:/test/my_local_path/sourceimages becomes $ASSETS/sourceimages where ASSETS=c:/test/my_local_path would be defined in your Maya.env file, and to swap over you just change it to ASSETS=e:/other/some_other_project.

This allows you to change it in the future without having to go back and edit all the files.
Alternatively, use a workspace.mel file and save all yours paths relative to that workspace.


Works like a charm, thanks a lot! It’s super fast now.

Indeed, this is just a rewrite of a much bigger script with a lot of other functions. I tested it on my local hard drive, I didn’t even bother to try on the server.

I will add this to my publish process. Do you know if I can change the project directory of Maya from the ASCII file?


If you’re working inside a project everything should just save relative to that workspace.mel file.
So you shouldn’t need to edit anything in the .ma files directly.

A quick test would be to setup a project, open up an existing file. And reset any of the file paths so that they’re relative. Then check what changes that makes in the .ma file after you save.

That should give you an idea of what you’d need to update in all the others.