6
$\begingroup$

In this simple addon example, a button is added to the Render tab of the Properties window

enter image description here

but when I click on it, I get the error message:

wm_operator_invoke: invalid operator call 'OBJECT_OT_my_operator'

What am I doing wrong? Here's my code:

import bpy

class OBJECT_OT_my_operator(bpy.types.Operator):
    bl_idname='object.my_operator'
    bl_label="My Operator"

    def exec(self, context):
        print("hello")        
        return {'FINISHED'}

def draw(self, context):      
    self.layout.operator('object.my_operator', text="Operator 1")

def register():
    bpy.utils.register_module(__name__)
    bpy.types.RENDER_PT_render.append(draw)

if __name__ == "__main__":
    register()
$\endgroup$
2
  • $\begingroup$ exec should be execute $\endgroup$ Feb 17, 2014 at 10:47
  • $\begingroup$ Just mark CoDemans answer since he already gave an extended explanation. $\endgroup$ Feb 17, 2014 at 11:24

1 Answer 1

11
$\begingroup$

As pink vertex pointed out, the method needs to called execute.

What happens here?

An operator added to a panel shows as button, and if you click it, Blender will try to invoke it by default (which means it looks for an invoke() method in the operator).

Since your operator has no invoke(), it will try to execute it instead (thus try to call execute()). Your operator doesn't have it, and Blender gives up with the error mesasge:

wm_operator_invoke: invalid operator call 'OBJECT_OT_my_operator'

So it means it couldn't find a method for the operator context (invoke for a button in a panel by default), nor an alternative (execute).

You can override the operator context in layouts if you need to. If your operator defines invoke() and execute() alongside, you might want a button in a panel that executes the operator, and not invoke it. Create a layout sub-element (column, row, ...) and set its operator_context attribute to the context you want to run it in (see API docs):

import bpy

class OBJECT_OT_my_operator(bpy.types.Operator):
    bl_idname = "object.my_operator"
    bl_label = "My Operator"

    def invoke(self, context, event):
        print("hello invoke")
        return {'FINISHED'}

    def execute(self, context):
        print("hello execute")        
        return {'FINISHED'}

def draw(self, context):
    layout = self.layout
    layout.operator(OBJECT_OT_my_operator.bl_idname, text="Operator 1 - invoke (default)")

    col = layout.column()
    col.operator_context = 'EXEC_DEFAULT'
    col.operator(OBJECT_OT_my_operator.bl_idname, text="Operator 1 - execute")


def register():
    bpy.utils.register_class(OBJECT_OT_my_operator)
    bpy.types.RENDER_PT_render.append(draw)

def unregister():
    bpy.utils.unregister_class(OBJECT_OT_my_operator)
    bpy.types.RENDER_PT_render.remove(draw)

if __name__ == "__main__":
    register()
$\endgroup$

You must log in to answer this question.

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