Hello developers! Please help to artist who trying to automate little things.
I found this magical timer that I want to use for autosave my textures in Texture Paint mode. So I found that my operator is bpy.ops.image.save_all_modified()
. But how i can to call it by timer? I tried hard but no result. Call operator once - so simple, but do it every N seconds - I rip my brain))
import bpy
def every_2_seconds():
print("Hello World")
return 2.0
bpy.app.timers.register(every_2_seconds)
Did you try substituting the line:
print("Hello World")
with:
bpy.ops.image.save_all_modified()
and run that? the timer will execute any line between the def
statement and the return
statement.
Yes. But no luck⌠Context error. What It wants?
Traceback (most recent call last):
File "/alfa/TMP/Test.blend/Text", line 5, in every_2_seconds
File "/ToshibaHDD/Soft/blender-git/build_linux/bin/2.83/scripts/modules/bpy/ops.py", line 201, in __call__
ret = op_call(self.idname_py(), None, kw)
RuntimeError: Operator bpy.ops.image.save_all_modified.poll() failed, context is incorrect
My script
import bpy
def every_2_seconds():
bpy.ops.image.save_all_modified()
return 2.0
bpy.app.timers.register(every_2_seconds)
The context must be coming from the wrong area, you can change context area like this:
context.area.type == "VIEW_3D"
For example, I guess you need the context to be âIMAGE_EDITORâ (check thatâŚ)
You may need to add bpy.
in front if you have not passed context to the function. Are you running this in a Text Editor? If so, the context area will not be correct for the Image Editor.
Try this and see how it goes.
See this link and this link.
Cheers, Clock.
EDIT:
Here is a code snippet I use quite a lot:
if context.area.type == "VIEW_3D":
if context.window_manager.pdt_run_opengl is False:
self.handle_add(self, context)
context.area.tag_redraw()
else:
self.handle_remove(self, context)
context.area.tag_redraw()
return {"FINISHED"}
self.report({"ERROR"}, PDT_ERR_NO3DVIEW)
return {"CANCELLED"}
Here is another that switches context area in a loop:
for i in range(0, len(freq_l) - 1):
bpy.context.area.type = "VIEW_3D"
# Do stuff in 3D View
bpy.context.area.type = "GRAPH_EDITOR"
# Do stuff in Graph Editor
bpy.ops.graph.sound_bake(
filepath=path,
low=low_f,
high=freq_l[i + 1],
attack=cm_node.attack,
release=cm_node.release,
threshold=cm_node.threshold,
use_accumulate=cm_node.use_accumulate,
use_additive=cm_node.use_additive,
use_square=cm_node.use_square,
sthreshold=cm_node.sthreshold
)
obj.select_set(state = False)
x_loc = x_loc + 0.1
bpy.context.area.type = "NODE_EDITOR"
# Do stuff in Node Editor
self.report({"INFO"}, f"{len(freq_l) - 1} Controls Created")
return {"FINISHED"}
Itâs deeper. Only this changed error to another:
import bpy
def every_2_seconds():
if bpy.context.mode == "TEXTURE_PAINT":
bpy.ops.image.save_all_modified()
return 2.0
bpy.app.timers.register(every_2_seconds)
Error
location: :-1
Error: File â/alfa/TMP/Test.blend/Textâ, line 9
return 2.0
^
IndentationError: unexpected indent
location: :-1
Post the blend file here please. It sounds like it doesnât like the indent, but unless I can run the code as you wrote it, I canât debug it⌠Why have you used context.mode == âTEXTURE_PAINTâ? The correct enumerator is âPAINT_TEXTUREâ. see this. How are you going to get that mode if the context is in the wrong Editor?
Iâll wait for your fileâŚ
I really mixed up commands. But I tried again with âPAINT_TEXTUREâ and doesnât work 
I do not allow any advertising cookies on my machineâŚ
Can you just post the blend file here, just drag it into a reply, there is no need to use websites that infest our machines with Cookies⌠Or use https://pasteall.org/blend/
OK, this is working for me:
You donât need the print statement, that is just so I see it working in my Terminal.
Hint always run Blender from a terminal when writing code, it shows all the error message (if you are not already doing this).
The enumerator is âPAINT_TEXTUREâ not âTEXTURE_PAINTâ.
EDIT:
I know it says âTexture Paintâ in the mode selector in 3D View, but the enumerator is tâother way around for some obscure reason⌠Ha! just to fool us.
Itâs not working) Please check state of textures (create they at first and save) - they doesnât saving. Print working for me as well, but originally trouble in bpy.ops.image.save_all_modified()
this worked for me, I added âtry and exceptâ because you can call save_all_modified only when there is something changed, I donât know if itâs right Iâm only artist myself but hey- itâs working 
import bpy
def every_2_seconds():
try:
bpy.ops.image.save_all_modified()
print("saved")
except:
pass
return 2.0
bpy.app.timers.register(every_2_seconds)
2 Likes
Thank you! Itâs really clever. Itâs working nice)
I trying to find how to start timer when bpy.ops.image.save_all_modified()
is able - now timer working permanent and textures saving in different time due timer and button not syncâŚ
I think you can even check if save_all_modified is available with bpy.ops.image.save_all_modified.poll()
so script could be edited like
import bpy
def every_2_seconds():
if bpy.ops.image.save_all_modified.poll():
bpy.ops.image.save_all_modified()
return 2.0
bpy.app.timers.register(every_2_seconds)
2 Likes