4
$\begingroup$

I would like to understand how to pass an object of type bpy.data to an operator, but I don't understand how to do it. I can pass a string, which will then retrieve what I am looking for, in this example I show how I pass a string to the operator, this string will retrieve the object. But I don't like it that way. And I don't know how to pass a bpy.data to the operator directly.

I want to clarify that it is not a question related to how to have the context.object, but I am interested in any type of object, so this is just an example to better define my question.

import bpy
from bpy.props import StringProperty


class SimpleOperator(bpy.types.Operator):
    
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
    
    object_name: StringProperty()
    
    #How to:
    #object: <---------------------
    
    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        
        #I can find the object like this:
        ob = bpy.data.objects[self.object_name]
        
        #But i want:
        # ob = self.object <---------------------
        
        return {'FINISHED'}


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        ob = context.object
        
        layout = self.layout

        op = layout.operator("object.simple_operator",text="Test")
        op.object_name = ob.name
        op.object = ob

def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.utils.register_class(HelloWorldPanel)

def unregister():
    bpy.utils.unregister_class(SimpleOperator)
    bpy.utils.unregister_class(HelloWorldPanel)

if __name__ == "__main__":
    register()
$\endgroup$
  • 1
    $\begingroup$ Would assume you tried object: PointerProperty(type=bpy.types.Object) only to get the error message saying you can't assign datablock pointers to an operator.... possibly explains why you never see this used in any operator. The idea si to use the operator / context paradigm and use context to reference objects. Going to have to grit your teeth and just put up with using method outlined in question, despite not liking it. $\endgroup$ – batFINGER Nov 28 '20 at 17:48
  • $\begingroup$ Great, So suppose I need to pass a bpy.data.node_groups and an relative inputs, I need to pass 2 arguments to the ops, example : group = bpy.data.node_groups[self.node_group_name] and input=group.inputs[self.input_int_idx] $\endgroup$ – Noob Cat Nov 28 '20 at 18:04
  • 1
    $\begingroup$ Added answer instead of long comment. Would make context members and use them in the op, instead of passing to the op as arguments. $\endgroup$ – batFINGER Nov 28 '20 at 18:10
5
$\begingroup$

Add context members for your op to use.

Would assume you tried

    object: PointerProperty(type=bpy.types.Object) 

only to get the error message saying you can't assign datablock pointers to an operator.... possibly explains why you never see this used in any operator. The idea is to use the operator / context paradigm and use context to reference objects

UILayout.context_pointer_set

Consider using context for this. Instead of passing it as an operator variable set a context member, in this case "foo" and use that in your operator.

Simple example that adds a row with button for each scene object. Each row has the context pointer "foo" set to respective object.

import bpy
from bpy.props import StringProperty, PointerProperty


class SimpleOperator(bpy.types.Operator):
    
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"    
    
    # This throws an error, because cannot save datablock ref to operator.
    #object: PointerProperty(type=bpy.types.Object)
    
    @classmethod
    def poll(cls, context):
        return getattr(context, "foo", False)

    def execute(self, context):
        
        #I can find the object like this:
        ob = context.foo
        print(ob)
        
        return {'FINISHED'}


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        ob = context.object
        
        layout = self.layout
        for ob in context.scene.objects:
            row = layout.row()
            row.context_pointer_set(name="foo", data=ob)
            row.operator("object.simple_operator", text=ob.name)


def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.utils.register_class(HelloWorldPanel)

def unregister():
    bpy.utils.unregister_class(SimpleOperator)
    bpy.utils.unregister_class(HelloWorldPanel)

if __name__ == "__main__":
    register()

Have used context.foo by way of example, because it is not a standard context member would recommend using

ob = getattr(context, "foo", None)

to give a null value when not set. have polled against it to disable operator if "foo" is not set.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.