The actual operator class is only accessible if it's defined in the same script, or imported from another file. It's not a standard Python class however, because it is derived from the Operator type:
import bpy
class PrimitiveManipulatorOperator(bpy.types.Operator):
bl_idname = "object.primitive_manipulator"
bl_label = "Primitive Manipulator"
def execute(self, context):
return {'FINISHED'}
type(PrimitiveManipulatorOperator) # returns <class 'bpy_types.OrderedMeta'>
Upon class registration of an operator class, it is made available as type as bpy.types.OBJECT_OT_primitive_manipulator
(which is the bl_idname
transformed from Python to C notation):
def register():
bpy.utils.register_class(PrimitiveManipulatorOperator)
# returns <class 'bpy_types.OrderedMeta'>
print(type(bpy.types.OBJECT_OT_primitive_manipulator))
# fails, the class name isn't used in case of operators
print(type(bpy.types.PrimitiveManipulatorOperator))
The interface to call operators is via bpy.ops
:
bpy.ops.object.primitive_manipulator()
# returns <class 'bpy.ops.BPyOpsSubModOp'>
type(bpy.ops.object.primitive_manipulator())
What can be confusing about bpy.ops
(which is <class 'bpy.ops.BPyOps'>
), is that hasattr()
will always return True
:
hasattr(bpy.ops, "object.primitive_manipulator") # True
hasattr(bpy.ops, "foobar") # also True
This is caused by the design of this module-like class and presumably necessary to make proper calls work.
The correct way to programmatically get a reference to the operator for a call is to getattr()
twice, as you want to retrieve a property and its sub-property:
op = getattr(getattr(bpy.ops, "object"), "primitive_manipulator")
op() # equivalent to bpy.ops.object.primitive_manipulator()
getattr(bpy.ops, "object.primitive_manipulator")
can't work because there is no property "object.primitive_manipulator"
, there's only "object"
, which in turn has the property "primitive_manipulator"
.
>>> type(getattr(bpy.ops, "object"))
<class 'bpy.ops.BPyOpsSubMod'>
>>> type(getattr(bpy.ops, "foo.bar"))
<class 'bpy.ops.BPyOpsSubMod'>
>>> type(getattr(getattr(bpy.ops, "object"), "primitive_manipulator"))
<class 'bpy.ops.BPyOpsSubModOp'>
You may want to resolve the operator name in a loop like this:
def get_operator(idname):
op = bpy.ops
for attr in idname.split("."):
op = getattr(op, attr)
return op
get_operator("object.primitive_operator")()
# if there's a poll() classmethod, you can also:
get_operator("object.primitive_operator.poll")()
# return a blank function to suppress AttributeErrors
# in case the operator idname does not exist
def get_operator_failsafe(idname):
op = bpy.ops
for attr in idname.split("."):
if attr not in dir(op):
return lambda: None
op = getattr(op, attr)
return op
get_operator_failsafe("foo.bar")()