How do I automatically execute a python script after Blender has fully loaded?
My script generates a scene based on a seed. I want to creat a couple thousand images but since Blender leaks memory after a hundred generations or so everything becomes significantly slower and eventually crashes. I want to migitate the problem by creating only x images per session and completely restart Blender after each session.
If I load the blend file manually and click the play button in the script editor, everything works as expected. When I try to call the script after startup, it crashes in add_curve_spirals.py
line 184, since context.space_data
is None
.
Since manually starting the script works fine, the problem is, that Blender is in some sort of wrong state. Starting it with or without GUI (--background
) does not affect this.
blender myfile.blend --python myscript.py
executes the script before the context is fully ready and thus produces the error.bpy.app.handlers.load_post
) calls my script after completely loading the file but still the context is not ready and it produces the error.bpy.app.timers.register(render_fun, first_interval=10)
.These are all the ways that I found to automatically execute a script. In every case the script seems to be executed too early / in the wrong state and all fail in the same way.
I want to stress that the script is not the issue here. Even if I could work around the particular line, many similar problems might follow and I don't want to rewrite my whole script. So what is the best way to automatically invoke it in the right state?
It turns out, that the problem was the execution context. This became clear after invoking the timed event manually, e.g. after the scene was loaded completely the timed event was still executed in a wrong context.
Since the crash happened in the add_curve_spirals
addon, the solution was to provide a context override the the operator invokation. The rest of my script was not equally sensitive to the context and worked just fine.
It was not clear to me, how exactly I should override the context, but this works for now (collected from other parts of the internet, so I don't understand all details):
def get_context():
# create a context that works when blender is executed from the command line.
idx = bpy.context.window_manager.windows[:].index(bpy.context.window)
window = bpy.context.window_manager.windows[idx]
screen = window.screen
views_3d = sorted(
[a for a in screen.areas if a.type == 'VIEW_3D'],
key=lambda a: (a.width * a.height))
a = views_3d[0]
# override
o = {"window" : window,
"screen" : screen,
"area" : a,
"space_data": a.spaces.active,
"region" : a.regions[-1]
}
return o
Final invocation: bpy.ops.curve.spirals(get_context(), spiral_type='ARCH', radius = radius, turns = turns, dif_z = dif_z, ...