2
$\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'm 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 object to that operator directly.

I want to clarify that this question isn't related to how to get the context.object, but rather I'm interested in getting 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$
4
  • 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, 2020 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, 2020 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, 2020 at 18:10
  • 2
    $\begingroup$ @RPaladin please be careful when making edits, notice that when you compare the diffs, you made an unnecessary change to the white spaces of the whole script which can add to confusion. And the def register & def unregister are now incorrectly indented into the class HelloWorldPanel $\endgroup$ Jul 13, 2022 at 0:40

1 Answer 1

6
$\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$
1
  • $\begingroup$ How is one supposed to pass ob (or "foo" in this case) when calling the operator from another script? Seems impossible since foo does not exist in context and context is readonly so it could never be set by anyone other than blender GUI. $\endgroup$ Sep 27 at 3:04

You must log in to answer this question.

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