From BlenderWiki
Introduction
In Blender 2.5 operators are automatically registered (using a metaclass), so Blender can find them. This is normally very convenient, but when you're creating operators dynamically it might cause problems.
Problems and solutions
Example of a normal operator declaration that is automatically registered correctly:
import bpy class Foobar(bpy.types.Operator): '''''' bl_idname = "foo.bar" bl_label = "FooBar!" def execute(self, context): print("foobar") return {'FINISHED'}
When you're dynamically creating operators, you might do something like this (which doesn't work):
import bpy my_names = ["Foo", "Bar"] def invoke(self, context, event): print(self.bl_description) return{'FINISHED'} for name in my_names: my_class = type(name, (bpy.types.Operator,), dict(bl_idname=name, bl_label=name+"!", bl_description=name)) setattr(my_class, 'invoke', invoke)
When you try to run the operator you get the error: "invalid operator call". The reason is that the automatic registering (the metaclass) is done immediately upon creating the class. So right after the line "my_class = type(...)". Adding methods or attributes after that, for example using setattr(), is too late. So the main thing to remember is:
setattr() doesn't work with the automatic registration of operators.
Below are two ways of doing it correctly:
import bpy my_names = ["Foo", "Bar"] def my_invoke(self, context, event): print(self.bl_description) return{'FINISHED'} for name in my_names: class my_class(bpy.types.Operator): bl_idname = name bl_label = name+"!" bl_description = name invoke = my_invoke
import bpy my_names = ["Foo", "Bar"] for name in my_names: class my_class(bpy.types.Operator): bl_idname = name bl_label = name+"!" bl_description = name def invoke(self, context, event): print(self.bl_description) return{'FINISHED'}
There is one final thing that might stop your script from working, and that's when the script is run as add-on. In your add-on you can't create operators from within the register() function.
Example of code that fails when run as add-on (but works correctly when run from the text-editor):
bl_addon_info = { "name": "FooBar", "category": "System"} import bpy def create_ops(): my_names = ["Foo", "Bar"] for name in my_names: class my_class(bpy.types.Operator): bl_idname = name bl_label = name+"!" bl_description = name def invoke(self, context, event): print(self.bl_description) return{'FINISHED'} def register(): create_ops() def unregister(): pass if __name__ == "__main__": register()
The solution is to simply create the operator classes in the module itself (this way they are defined when the module is imported), not in a function definition:
bl_addon_info = { "name": "FooBar", "category": "System"} import bpy my_names = ["Foo", "Bar"] for name in my_names: class my_class(bpy.types.Operator): bl_idname = name bl_label = name+"!" bl_description = name def invoke(self, context, event): print(self.bl_description) return{'FINISHED'} def register(): pass def unregister(): pass
Summary
- Don't use setattr() to set the poll/invoke/execute functions.
- Don't create operators from within the register() function.
References
Discussion on the mailinglist
Correct link to script mentioned in above discussion