3
$\begingroup$

I would like to run a python script, which adds every frame a new Mask-modifier to an object (and deleting the old). While following script works if the code runs in interactive blender window, during rendering it leads to an error message when it calls modifier_move_up().

import bpy

object_name = "Cube"

bpy.app.handlers.frame_change_post.clear()

def my_handler(scene):

    print("Frame Change", bpy.context.scene.frame_current )

    obj = bpy.data.objects[object_name]

    # delete mask-modifier and add new to last but one position
    if obj.modifiers.find("Mask")+1: 
        obj.modifiers.remove(obj.modifiers.get("Mask"))

    obj.modifiers.new("Mask", type="MASK")
    #################################################
    bpy.ops.object.modifier_move_up(modifier="Mask")
    #################################################

bpy.app.handlers.frame_change_post.append(my_handler)

Error message:

RuntimeError: Operator bpy.ops.object.modifier_move_up.poll() failed, context is incorrect

As far as I understand, I should override the context, but I don't know how exactly and with which parameters.

According to this question (How do I override context for bpy.ops.mesh.loopcut?) I added an override, but with no effect.

import bpy

object_name = "Cube"

bpy.app.handlers.frame_change_post.clear()

win      = bpy.context.window
scr      = win.screen
areas3d  = [area for area in scr.areas if area.type == 'VIEW_3D']
region   = [region for region in areas3d[0].regions if region.type == 'WINDOW']

override = {'window':win,
            'screen':scr,
            'area'  :areas3d[0],
            'region':region[0],
            'scene' :bpy.context.scene,
            }

def my_handler(scene):

    print("Frame Change", bpy.context.scene.frame_current )

    obj = bpy.data.objects[object_name]

    # delete mask-modifier and add new to last but one position
    if obj.modifiers.find("Mask")+1: 
        obj.modifiers.remove(obj.modifiers.get("Mask"))

    obj.modifiers.new("Mask", type="MASK")
    #################################################
    bpy.ops.object.modifier_move_up(override, modifier="Mask")
    #################################################

bpy.app.handlers.frame_change_post.append(my_handler)

While running this code in blender I get after frame change following messages (the code itself works):

PyContext 'modifier' not found PyContext 'object' not found PyContext 'modifier' not found PyContext 'object' not found PyContext 'object' not found

While I'm try to render this part of the messages changes to...

PyContext 'modifier' not found PyContext 'object' not found PyContext 'active_object' not found

... followed by the mentioned "context is incorrect" error message.

What am I doing wrong?

$\endgroup$

1 Answer 1

4
$\begingroup$

Match the area that the operator is called from in UI.

The operator bpy.ops.object.modifier_move_up when run from the UI is done in the properties area. (area.type == 'PROPERTIES'). Properties has some extra context members, context.modifiers being one of those.

As well as "modifier" the error message is also complaining about "object" not being a member of over-ridden context.

import bpy

object_name = "Cube"

bpy.app.handlers.frame_change_post.clear()

win = bpy.context.window
scr = win.screen
areas3d = [area for area in scr.areas if area.type == 'PROPERTIES']
region = [region for region in areas3d[0].regions if region.type == 'WINDOW']

override = {'window': win,
            'screen': scr,
            'area': areas3d[0],
            'region': region[0],
            }

def my_handler(scene):

    print("Frame Change", scene.frame_current)
    obj = scene.objects.get(object_name)
    if obj is None:
        return
    mod = obj.modifiers.get("Mask")
    # delete mask-modifier and add new to last but one position
    if mod:
        obj.modifiers.remove(mod)

    mod = obj.modifiers.new("Mask", type="MASK")
    override["modifier"] = mod
    # perhaps works without these 2 but hey???
    override["object"] = obj
    override["active_object"] = obj
    # avoid hassles by adding scene here
    override["scene"] = scene
    #################################################
    bpy.ops.object.modifier_move_up(override, modifier="Mask")
    #################################################

bpy.app.handlers.frame_change_post.append(my_handler)
$\endgroup$

You must log in to answer this question.

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