How do I call an operator from a different file?

I have an add-on that creates new Materials and adds and connects all the required Nodes. The goal is to keep it all in code, no appending from .blends.

I want to replace a series of Nodes common to all the Materials with a shared Group node. I’ve got a working script that checks to see if the Group already exists, adds it if it does, and creates it if it doesn’t — about 80 lines of code.

If I add this block into each of the 23 individual material files, everything works fine. But I’d like to have those 80 lines of code in one file, and just call it as needed.

So, I have a file called SpecularGroupNode.py that has the operator and script, and it starts with

class SpecularGroup(bpy.types.Operator):
    """Add/Get Specular Group Node"""
    bl_label = "Specular Node Group"
    bl_idname = 'node.specular_group_operator'
    def execute(self, context):
        ...

Inside __init__.py, I import it with

from .SpecularGroupNode import *

and I register the class SpecularGroup, all good so far.

But I’m stuck on how to call the operator.

If it were a button in a panel, I would just write

row.operator("node.specular_group_operator", text="Specular Group")

and Bob’s your uncle, cool.

Best I’ve been able to gather is to call it from inside my Material file with

bpy.ops.node.specular_group_operator

but this returns nothing, not even an error.

My brain’s a bit foggy after grinding on this add-on for the last few hours, but I presume I’ve got the wrong approach. For all my Googling and looking through other add-ons, I still haven’t found the “Ah-ha!” that clearly and specifically denotes the correct approach.

If anyone can offer the solution, I would be hugely grateful.

And/Or if you have the link to an online reference or tutorial on this very topic, that would be amazing.

Thanks in advance!

All operators return something. It’s either returning FINISHED because it worked, CANCELLED because of some specific reason, or it will raise an exception if there’s an error. My guess is that you’re not calling it like a function, so the python interpreter is just ignoring it. Don’t forget your parenthesis:

bpy.ops.node.specular_group_operator()

As requested, a link to the docs.

1 Like

Ah, thanks!

Yes, I misspoke. It was returning an error:
RuntimeError: Error: Python: RuntimeError: class NODE_OT_specular_group_operator, function execute: incompatible return value , , Function.result expected a set, not a NoneType

Anyway, I took a break, ate something, read your comment, added the parentheses, commented out most of SpecularGroupNode.py, and slowly added it back in line by line, solving each error that came up, and I’ve got it working!!! :partying_face:

I’m about 650 days in since I started working in Python, and I’m loving it, but every so often I get tripped up by some really basic mistake. :roll_eyes:

It may be a small thing, but feedback from folks like you helps keep me motivated, so thanks again for your help!

yeah that specific error means that in your execute() function you weren’t returning anything. gotta make sure you’re always returning {'FINISHED'} at the end of an operator (curly braces not optional, otherwise you’ll get the exact same error but str instead of NoneType. When in doubt post your code here, no shame in asking for help :slight_smile:

1 Like