14
$\begingroup$

When I run

import bpy
bpy.ops.wm.read_homefile()

and then I replace the above with this (in the same text data block)

import bpy
rrr = bpy.ops.object.select_all(action='SELECT')
print("select_all result:", rrr)
print(">>>>>>>>>> bpy.context:", bpy.context)
print(">>>>>>>>>> bpy.context.object:", bpy.context.object)
print(">>>>>>>>>> bpy.context.object.name:", bpy.context.object.name)

and run it, I get this

select_all result: {'FINISHED'}
>>>>>>>>>> bpy.context: <bpy_struct, Context at 0x000000EEA420B5C8>
>>>>>>>>>> bpy.context.object: <bpy_struct, Object("Cube")>
>>>>>>>>>> bpy.context.object.name: Cube

However, when I run this (same code but merged)

import bpy
bpy.ops.wm.read_homefile()
rrr = bpy.ops.object.select_all(action='SELECT')
print("select_all result:", rrr)
print(">>>>>>>>>> bpy.context:", bpy.context)
print(">>>>>>>>>> bpy.context.object:", bpy.context.object)
print(">>>>>>>>>> bpy.context.object.name:", bpy.context.object.name)

I get this

select_all result: {'PASS_THROUGH'}
>>>>>>>>>> bpy.context: <bpy_struct, Context at 0x000000EEA420B5C8>
Traceback (most recent call last):
  File "\Text", line 7, in <module>
AttributeError: 'Context' object has no attribute 'object'

Why does that happen?

Is there a way to make the code after bpy.ops.wm.read_homefile() work "normally"?

Edit:
It seems that bpy.ops.wm.read_homefile() effectively "clears" the context - the bpy.context.area is None.

So the new question is how to bring the context back to the correct area?

Edit 2: I have found a workaround that searches for 3D View area and makes it current context - and here is the dubious part - by calling bpy.ops.screen.screen_full_area():

import bpy
bpy.ops.wm.read_homefile()
havesetthecontext = False
for window in bpy.context.window_manager.windows:
    screen = window.screen
    for area in screen.areas:
        print("area=", area)
        if area.type == 'VIEW_3D':
            override = {'window': window, 'screen': screen, 'area': area}
            bpy.ops.screen.screen_full_area(override)   # toggle to maximize
            bpy.ops.screen.screen_full_area()           # toggle back (must not use overridden context, else it will crash!)
            havesetthecontext = True
            break

if havesetthecontext:
    rrr = bpy.ops.object.select_all(action='DESELECT')
    print("select_all result:", rrr)
    print(">>>>>>>>>> bpy.context:", bpy.context)
    print(">>>>>>>>>> bpy.context.object:", bpy.context.object)
    print(">>>>>>>>>> bpy.context.object.name:", bpy.context.object.name)
else:
    print("Could not set the context to 3D View!")

Now, isn't there a way to set a context directly, something like bpy.context.set(override)?

Edit 3:
The above workaround is unstable (occasionally crashes Blender) unless Load UI is disabled.
So, add this line before calling bpy.ops.wm.read_homefile():

bpy.context.user_preferences.filepaths.use_load_ui = False

That, of course, kind of kills the purpose of reloading startup file, unfortunately.

Oh, and the same issues appear when calling read_factory_settings().

When I run the screen_full_area() stuff from load_handler then it does not crash, however, in the "main" code the bpy.context.area is still None - and when I do screen_full_area() stuff there too, it crashes again.

I suspect that crashing is due to some code in screen_full_area(), not the context changing, so we are back to the question is there a way to set the context directly?

$\endgroup$
7
  • 1
    $\begingroup$ I believe it's a matter of time you have to wait until the loading is done, the code is executed while the loading is done $\endgroup$
    – Chebhou
    Commented Apr 27, 2016 at 14:57
  • $\begingroup$ you may try to append you code to the handler load_post to be executed after loading a new file $\endgroup$
    – Chebhou
    Commented Apr 27, 2016 at 15:08
  • 2
    $\begingroup$ @Chebhou, thanks, but it looks like read_homefile() returns only after the file is loaded. I can access the Cube from the file immediately after the read_homefile() line. I will try the load_post handler though ... $\endgroup$
    – spacer
    Commented Apr 27, 2016 at 20:00
  • $\begingroup$ @Chebhou, nope, load_post handler also says bpy.context.area = None. $\endgroup$
    – spacer
    Commented Apr 27, 2016 at 20:06
  • 2
    $\begingroup$ I have found a workaround-like solution using context override with screen_full_area operator called twice ... $\endgroup$
    – spacer
    Commented Apr 27, 2016 at 21:32

1 Answer 1

2
$\begingroup$

Try this script it works for me on Blender 3.4. You have to first add the load_post handler and then call bpy.ops.wm.read_homefile() so that your code only triggers after loading is complete and the context has been properly set.

import bpy
from bpy.app.handlers import persistent

bpy.app.handlers.load_post.clear()

@persistent
def load_handler(dummy):
    print("Load Handler:", bpy.data.filepath)
    bpy.app.handlers.load_post.remove(load_handler)

    result = bpy.ops.object.select_all(action='SELECT')

    print("select_all result:", result)
    print(">>>>>>>>>> bpy.context:", bpy.context)
    print(">>>>>>>>>> bpy.context.object:", bpy.context.object)
    print(">>>>>>>>>> bpy.context.object.name:", bpy.context.object.name)
    print(">>>>>>>>>> bpy.context.screen:", bpy.context.screen)
    for index, area in enumerate(bpy.context.screen.areas):
        print(f">>>>>>>>>> bpy.context.screen.areas[{index}]:", area)
    print(">>>>>>>>>> bpy.context.area:", bpy.context.area)

bpy.app.handlers.load_post.append(load_handler)
bpy.ops.wm.read_homefile()

The bpy.context.area may be None due to a bug, I'm not sure, but that is fine because you can still access all the areas in bpy.context.screen.areas list.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .