14

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?

spacer
  • 901
  • 7
  • 21
  • 1
    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 – Chebhou Apr 27 '16 at 14:57
  • you may try to append you code to the handler load_post to be executed after loading a new file – Chebhou Apr 27 '16 at 15:08
  • 2
    @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 ... – spacer Apr 27 '16 at 20:00
  • @Chebhou, nope, load_post handler also says bpy.context.area = None. – spacer Apr 27 '16 at 20:06
  • 2
    I have found a workaround-like solution using context override with screen_full_area operator called twice ... – spacer Apr 27 '16 at 21:32
  • I can't believe this question is not solved yet. Suffering from the same problem in 2021. :P And from the Blender 2.80, you should use bpy.context. preferences.filepaths.use_load_ui = False – dalbom Oct 22 '21 at 11:27
  • i suspect read_homefile and read_factory_settings will have the same resolution, I put a bounty on this topic over here https://blender.stackexchange.com/questions/220523/is-there-a-recommend-way-to-repair-or-recreate-a-valid-context-after-using-bpy – ThorSummoner Jun 05 '22 at 23:29

1 Answers1

2

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(&quot;select_all result:&quot;, result)
print(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; bpy.context:&quot;, bpy.context)
print(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; bpy.context.object:&quot;, bpy.context.object)
print(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; bpy.context.object.name:&quot;, bpy.context.object.name)
print(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; bpy.context.screen:&quot;, bpy.context.screen)
for index, area in enumerate(bpy.context.screen.areas):
    print(f&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; bpy.context.screen.areas[{index}]:&quot;, area)
print(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; bpy.context.area:&quot;, 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.

Harry McKenzie
  • 10,995
  • 8
  • 23
  • 51