Some Blender operators can only be called from the workspace for which they are intended.
If you call from the Python console, for example, an operator intended only for working in the 3D Viewport area, the operator will not be executed:
1 2 3 |
bpy.ops.wm.toolbar() # {'CANCELLED'} |
or it will fail with an error message about the incorrect context:
1 2 3 |
bpy.ops.view3d.background_image_add() # RuntimeError: Operator bpy.ops.view3d.background_image_add.poll() failed, context is incorrect |
However, we can still execute operators from a non-native working area. To do this, we can pass the first implicit parameter to any operator – a pointer to the context of the area in which this operator should be executed. This parameter commonly named the “overridden context”.
This method is suitable for Blender version 3.1 and earlier. For Blender 3.2 and later, we must use the temp_override() method.
The overridden context is a dictionary with a set of elements that describe the desired area.
For example, for the 3D viewport area, the overridden context should be compiled as follows:
1 2 3 4 5 6 7 8 9 10 |
import bpy override_context = bpy.context.copy() area = [area for area in bpy.context.screen.areas if area.type == "VIEW_3D"][0] override_context['window'] = bpy.context.window override_context['screen'] = bpy.context.screen override_context['area'] = area override_context['region'] = area.regions[-1] override_context['scene'] = bpy.context.scene override_context['space_data'] = area.spaces.active |
The main thing is to specify the desired working area – in our case, the 3D viewport “VIEW_3D” area. Of course, at least one such area must be open in Blender windows.
Having received the structure of the overridden context, we can call the operator, passing it as the first parameter:
1 |
bpy.ops.wm.toolbar(override_context) |
The full code that will correctly execute from the Blender Text Editor area and opens a tools panel in the 3D Viewport area:
1 2 3 4 5 6 7 8 9 10 11 12 |
import bpy override_context = bpy.context.copy() area = [area for area in bpy.context.screen.areas if area.type == "VIEW_3D"][0] override_context['window'] = bpy.context.window override_context['screen'] = bpy.context.screen override_context['area'] = area override_context['region'] = area.regions[-1] override_context['scene'] = bpy.context.scene override_context['space_data'] = area.spaces.active bpy.ops.wm.toolbar(override_context) |
hi Nikita,
thanks for this precious piece of code, i’ve tested it and work perfectly fine, exept when i tried to override another context: i wanted my operator execute in UV context:
i tried:
area = [area for area in bpy.context.screen.areas if area.type == “UV”][0]
area = [area for area in bpy.context.screen.areas if area.type == “UV”][2]
and for both system console returns this error:
“IndexError: list index out of range”, do you ghve an idea what i’m doing wrong?
thanks for your help;)
Hi ,
1) i’m sorry it work perfectly, my area type was wrong, it works like this:
area = [area for area in bpy.context.screen.areas if area.type == “IMAGE_EDITOR”][0]
2) is it possible to make it work without having an “IMAGE_EDITOR” open in the viewport?
as it is open in the UV editing workspace?
Bests and thanks again;)
Hi!
You can’t get the context of the window without this window itself.
You can try to open the required window area, copy the context, next close the area. But I’m not sure if it will work.
Hi, many thanks for sharing your code knowledge:
I’m trying for few days to switch a tab of the properties editor with a script (called from the 3D View) but it’s not working… I tried many many things and start to think if really it is possible. Here is my script in case you would want to give me a hint:
Hi!
You don’t need to play with context overriding if you only need to switch the tab in the Properties window. Just get the required area and change the type of the window context.
Awesome! it’s just working, after three days of tries you made my day
Since I have a reference of the area with l_area variable can I only apply the change to this one and not all Properties editor if I have more than one opened?
Of course, if you already have a pointer to the required area you don’t need to find it twice.
This code only change the tab of Properties editor that already exist and not the new one created by the code.
Try to redraw your generated area with tag_redraw.
useful as always I did this
https://github.com/1C0D/Override-blender_addon
Thank you soooo much for sharing how to override the context! None of the old codes I tried worked, but yours worked wonders!! I have written an addon that helps obj->fbx file conversion process, and planning to post it under GNU license (because the addon I used to write mine was under GNU. Is it ok to include the below override snippet for my addon? I will link your website as a comment. Thank you so much!
override_context = bpy.context.copy()
area = [area for area in bpy.context.screen.areas if area.type == “VIEW_3D”][0]
override_context[‘window’] = bpy.context.window
override_context[‘screen’] = bpy.context.screen
override_context[‘area’] = area
override_context[‘region’] = area.regions[-1]
override_context[‘scene’] = bpy.context.scene
override_context[‘space_data’] = area.spaces.active
You can use the code from my articles any way you like.
Thank you sooooo much! You are so kind:)