I keep on getting context errors in the Blender Python API.
I don't understand the issue of the context in the API, how do I know which is the correct context?
Thanks!
Blender Stack Exchange is a question and answer site for people who use Blender to create 3D graphics, animations, or games. It only takes a minute to sign up.
Sign up to join this communityI keep on getting context errors in the Blender Python API.
I don't understand the issue of the context in the API, how do I know which is the correct context?
Thanks!
The context members available depend on the area of blender which is currently being accessed.
See bpy.context
Many operators have a “poll” function which may check that the mouse is a valid area or that the object is in the correct mode (Edit Mode, Weight Paint etc). When an operator’s poll function fails within python, an exception is raised.
See Operator.poll()
More about using Operators and why you experience poll-fails (mouse not over right screen area or wrong mode / other pre-condition). Also see the Gotchas section of the API docs about that.
You can either:
bl_options
must not contain 'INTERNAL'
)Area.type
temporarilyDoesn't seem to work for this operator?! It adds a background but without name / texture.
import bpy
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
override = bpy.context.copy()
override['area'] = area
bpy.ops.view3d.background_image_add(override, name="BG", filepath=r"image.png")
break
By the way:
You can pass an empty dict (like bpy.ops.example.operator({})
), which usually prints warnings to the system console about the context members missing. You need to pass these members and repeat until it doesn't complain anymore. But beware of certain operators, which require scene bases - if you don't provide a reference to them, Blender will crash to desktop before you even find out they are needed.
area = bpy.context.area
old_type = area.type
area.type = 'VIEW_3D'
bpy.ops.view3d.background_image_add(name="BG", filepath=r"image.png")
area.type = old_type
Similar to the override, you need a 3D View instance, in this case its space data (because this is the place where backgrounds reside). The following code takes the first 3D View of the current screen layout (if there's one), adds a new background and sets the image to an image datablock:
import bpy
filepath = r"C:\path\to\image.png"
img = bpy.data.images.load(filepath)
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
space_data = area.spaces.active
bg = space_data.background_images.new()
bg.image = img
break
object_bases
in context overrides or Blender would crash.
$\endgroup$
Here's to add to @CodeManX's answer. If you get a runtime error that looks like this:
RuntimeError: Operator bpy.ops. ... .poll() failed, context is incorrect
which is specifically in your case:
RuntimeError: Operator bpy.ops.view3d.background_image_add.poll() failed, context is incorrect
You can use the following script to override context. Make sure to use the correct Area Type
which is assigned to area_type
in this script and make sure this area is visible or open in your screen. For example, if you call a bpy.ops
function that directly manipulates the Dope Sheet, you have to make sure this editor is actually open and set area_type = 'DOPESHEET'
.
Since you are calling bpy.ops.view3d.background_image_add()
which directly manipulates the 3d Viewport, you have to make sure it is actually open and set area_type = 'VIEW_3D'
. It is easy to find out the enum for the area type; just switch the editor type and you will see the type in the Info Editor
which is open by default in the lower left corner of the Scripting Tab
Take note that in the legacy context override you have to pass the override
dictionary object as first parameter to the bpy.ops
function.
import bpy
area_type = 'VIEW_3D' # change this to use the correct Area Type context you want to process in
areas = [area for area in bpy.context.window.screen.areas if area.type == area_type]
if len(areas) <= 0:
raise Exception(f"Make sure an Area of type {area_type} is open or visible in your screen!")
override = {
'window': bpy.context.window,
'screen': bpy.context.window.screen,
'area': areas[0],
'region': [region for region in areas[0].regions if region.type == 'WINDOW'][0],
}
bpy.ops.view3d.background_image_add(override)
Use bpy.context.temp_override
for blender 3.2 and beyond.
import bpy
area_type = 'VIEW_3D' # change this to use the correct Area Type context you want to process in
areas = [area for area in bpy.context.window.screen.areas if area.type == area_type]
if len(areas) <= 0:
raise Exception(f"Make sure an Area of type {area_type} is open or visible in your screen!")
with bpy.context.temp_override(
window=bpy.context.window,
area=areas[0],
region=[region for region in areas[0].regions if region.type == 'WINDOW'][0],
screen=bpy.context.window.screen
):
bpy.ops.view3d.background_image_add()
import bpy
# ========================================================
# Determine whether Blender is 3.2 or newer and requires
# the temp_override function, or is older and requires
# the context override dictionary
# ========================================================
def use_temp_override():
version = bpy.app.version
major = version[0]
minor = version[1]
return not (major < 3 or (major == 3 and minor < 2))
window = bpy.context.window
screen = window.screen
def get_areas(type):
return [area for area in screen.areas if area.type == type]
def get_regions(areas):
return [region for region in areas[0].regions if region.type == 'WINDOW']
def execute_main_script():
area_type = 'VIEW_3D' # change this to use the correct Area Type context you want to process in
areas = get_areas(area_type)
if len(areas) <= 0:
raise Exception(f"Make sure an Area of type {area_type} is open or visible in your screen!")
if use_temp_override(): # execute using new temp override
with bpy.context.temp_override(window=window, area=areas[0], region=get_regions(areas)[0], screen=screen):
bpy.ops.view3d.background_image_add()
else: # execute using legacy override
override = {
'window': window,
'screen': screen,
'area': areas[0],
'region': get_regions(areas)[0],
}
bpy.ops.view3d.background_image_add(override)
print("Execute Main Script =================> ")
execute_main_script()
bpy.ops
Please note that you should always try to avoid bpy.ops
functions whenever possible, that is, avoid them when there is an alternative solution because an overuse of these functions can potentially cause performance issues.
bpy.context.area.ui_type = area_type
$\endgroup$
Aug 3, 2022 at 8:55
use_temp_override()
can be reduced to if bpy.app.version >= (3, 2, 0):
or if hasattr(bpy.context, "temp_override"):
$\endgroup$
if hasattr(bpy.context, "temp_override"):
is even better as we can get rid of the hard-coded version values. thanks for sharing!
$\endgroup$
Dec 21, 2022 at 8:21
bpy.context
or added it via layout.context_pointer_set
but I think it's fait to assume no one would do that :)
$\endgroup$