Here is what I need to do: I need to add a button to this context menu (the one you get when you right click on any button):

Context Menu

like the one I added here at the bottom. I am using this code from the blender docs to make that work. Now I need to be able to reference the blender command from the button that has been clicked on and use that in my code. I have been looking for the source code for the Copy Python Command button that is shown above my custom button, but I haven't been able to find it. That button pretty much does the same thing that I need to do, so if anyone knows where that source code is, or just how to implement something similar, I would really appreciate it!



The answer is in the example code.

When executed over the splash screen button, it prints to console

Note have added

def dump(obj, text):
    print(text, obj)

to the dump method to inform which of the button context members are not None

button_operator <bpy_struct, WM_OT_splash at 0x7f474dff47e8>
<bpy_struct, WM_OT_splash at 0x7f474dff47e8>.__doc__ = None
<bpy_struct, WM_OT_splash at 0x7f474dff47e8>.__module__ = bpy.types
<bpy_struct, WM_OT_splash at 0x7f474dff47e8>.__slots__ = ()
<bpy_struct, WM_OT_splash at 0x7f474dff47e8>.bl_rna = <bpy_struct, Struct("WM_OT_splash") at 0x7f477da08e48>
<bpy_struct, WM_OT_splash at 0x7f474dff47e8>.rna_type = <bpy_struct, Struct("WM_OT_splash") at 0x7f477da08e48>

Going by blenders naming convention the class instance above of WM_OT_splash correlates to window manager operator type splash --> the registered operator bpy.ops.wm.splash() with bl_idname = "wm.splash".

Ok can change up the script to get the operator from the button context.

def execute(self, context):
    op = getattr(context, "button_operator")
    if op:
    return {'FINISHED'}

Lets run this new code over the run script button

<bpy_struct, TEXT_OT_run_script at 0x7f9606bf4a68>

Looks familiar off to the python console. Examples of the active operator (last registered operator run) and how to get the options used in the last run of the operator. IMO the py console is a great place to peck around and work out how things work. The example script that prints the dir of available properties is another

>>> op = C.active_operator
>>> op
<bpy_struct, Operator("TEXT_OT_run_script") at 0x7f4755ffa708>

>>> op.rna_type
<bpy_struct, Struct("TEXT_OT_run_script") at 0x7f477c30cde8>

>>> C.window_manager.operator_properties_last("text.run_script")
<bpy_struct, TEXT_OT_run_script at 0x7f9606bf4b08>

To get there quickly, Feel there is a nicer way to do this, anyway

Get the operator, get its bl_idname from the class name. If there is a property attached to the button it is reflected in the button context. From the operator get its properties (minus rna_type) to find which belong to the operator.

Get the operator from bpy.ops invoke it and use the settings of the button.

Following writes info re the operator and also invokes it.

def execute(self, context):
    op = getattr(context, "button_operator")
    if op:
        foo, bar = op.bl_rna.identifier.split("_OT_")
        keys = set(op.bl_rna.properties.keys()) - {'rna_type'}
        kwargs = {k : getattr(op, k) for k in dir(op) if k in keys}
        print(foo.lower(), bar, kwargs)
        op_callable = getattr(getattr(bpy.ops, foo.lower()), bar)
        # run the op
        op_callable('INVOKE_DEFAULT', **kwargs)
    return {'FINISHED'}

Which if run over the add custom property to workspace in 3D view UI, prints the following to console

wm properties_add {'data_path': 'workspace'}

and runs the operator adding a new custom property to the workspace.

  • $\begingroup$ Great! This is super helpful thanks for taking the time to respond. It is a great idea to just use the class instance naming convention. I am worried though, what if there is some external add-on with operators that isn't using this convention? I guess I can check to see if a operator follows that naming convention, but it might limit the amount of buttons this works for. Thanks again! $\endgroup$
    – andesign
    Dec 31 '20 at 18:07
  • 1
    $\begingroup$ Will find when registered a class is given class name from bl_idname , the SimpleOperator example in the templates is an example. When registered it is ` bpy.types.OBJECT_OT_simple_operator $\endgroup$
    – batFINGER
    Dec 31 '20 at 18:09
  • $\begingroup$ Works like a charm thanks! $\endgroup$
    – andesign
    Dec 31 '20 at 18:14

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.