Reputation: 3495
I've started an autosave script editor script (using Maya 2014), but it's really unstable and can crash if something happens at the same time as a save. I also just realised crashes will happen even when not saving, so I tried to find what the actual problem was, and ended up with barely any code left but still able to replicate it.
My idea for the code is to run a background thread, where it'll loop and backup the scripts at an interval, but check a value every second to make sure it's not been paused or cancelled (cancelled will stop the loop).
I presume the problem is something to do with how background threads work in Maya, as it can crash if loading/closing the script editor window, or switching tabs on the render view settings (at least with Mental Ray selected, since it seems to take longer loading tabs than the default renderer). I presume there's other ways, but those are the ones that were really easy to find.
After getting it down to just time.sleep()
in a while loop, it really doesn't make sense to me as to why it should be causing a crash. I also used a different sleep function that does while time.time()>startTime+1
, to make sure it wasn't the time module, but it still caused crashes.
Here is the cut down code if anyone wants to try it, once you start the thread with AutoSave.start()
, if you continuously load and close the script editor window, you should eventually get a runtime error (that says R6025 pure virtual function call). It may take multiple attempts, but it always seems to eventually happen.
import threading, time
import pymel.core as pm
class AutoSaveThread(object):
def __init__( self ):
thread = threading.Thread(target=self.run, args=())
thread.daemon = True
thread.start()
def run(self):
while True:
time.sleep(1)
print "Open and close the script editor enough times and this will crash"
class AutoSave:
@classmethod
def start( self ):
AutoSaveThread()
I have a dozen or so tabs open so loading/closing takes a bit longer than if I had none, this could potentially increase the time window in which crashes can happen.
For the record, here is the bit of code built into Maya that will always run whenever the script editor window is closed. I thought it may have something to do with my modified version of it saving, then this trying to save at the same time, but it's still crashing with nothing happening in the loop.
global proc syncExecuterBackupFiles(){
global string $gCommandExecuter[];
global string $executerBackupFileName;
if(`optionVar -q saveActionsScriptEditor`) {
// clear the script editor temp dir first before writing temp files
string $scriptEditorTempDir = (`internalVar -userPrefDir` + "scriptEditorTemp/");
string $tempFiles[] = `getFileList -folder $scriptEditorTempDir`;
string $file;
for ($file in $tempFiles) {
sysFile -delete ($scriptEditorTempDir + $file);
}
// save all the executer control text to files
int $i = 0;
for($i = 0; $i < size($gCommandExecuter); $i++) {
cmdScrollFieldExecuter -e -storeContents $executerBackupFileName $gCommandExecuter[$i];
}
}
}
Upvotes: 0
Views: 1689
Reputation: 41
import threading
import time
import maya.utils as utils
run_timer = True
run_num = 0
def example(interval = 10):
global run_timer;global run_num;
def your_function_goes_here():
print "hello",run_num
run_num +=1
while run_timer:
time.sleep(interval)
utils.executeDeferred(your_function_goes_here)
t = threading.Thread(None, target = example, args = (1,) )
t.start()
# stop :
# run_timer = False
Upvotes: 0
Reputation: 590
Try wrapping your call to print
in pymel.mayautils.executeDeferred
or maya.utils.executeDeferred
so that it is executed on the main UI thread.
if you continuously load and close the script editor window, you should eventually get a runtime error (that says R6025 pure virtual function call). It may take multiple attempts, but it always seems to eventually happen.
I was able to confirm this behavior on Maya 2012, and I doubt it's version specific.
My bet is that your test call to print
is what is actually causing Maya to crash, because even though print
is normally just a python statement, Maya has some sort of hook into it to update the Script Editor's Output Window (and potentially the Command Response bar) with the string you are printing, which are both running on the main UI Thread.
From the Autodesk Knowledge article "Python and threading":
Maya API and Maya Command architectures are not thread-safe. Maya commands throw an exception if they are called outside the main thread, and use of the OpenMaya API from threads other than the main one has unforeseen side effects.
By passing your print
statement to pymel.mayautils.executeDeferred I've (at least thus far, who knows with Maya ;-) ) been unable to cause a crash.
import threading, time
import pymel.core as pm
import pymel.mayautils # like maya.utils, for executeDeferred
# Set to False at any time to allow your threads to stop
keep_threads_alive = True
def wrapped_print():
print "Opening and closing the script editor shouldn't make this crash\n"
class AutoSaveThread(object):
def __init__(self):
thread = threading.Thread(target=self.run)
thread.start()
def run(self):
while keep_threads_alive:
time.sleep(1)
pymel.mayautils.executeDeferred(wrapped_print)
...
The only side-effect of wrapping specifically a print
statement is that it no longer echoes to the Command Response bar. If preserving that behavior is important to you just use pymel.mel.mprint
instead.
Upvotes: 3