Blender API error

I’m making a quite standard addon for adding objects and I’m trying to add a button that lets you set the color of an object via a popup. Since I’m new to python I’ve just pasted together code from different tutorials on youtube. No errors reported when running the script but when I’m using the button for choosing the color:

Python: RuntimeError: class ADDONNAME_OT_addbasic_operator, function execute: incompatible return value , , Function.result expected a set, not a NoneType

I don’t understand this at all. Need some help to fix it and how to improve the code if possible. I would prefer if the “Add Shader” button were part of the Options menu but I need to get rid of the errors first.

My code:

import bpy


    #Skapar klass för huvudpanelen 
class MainPanel(bpy.types.Panel):
    bl_label = "Object Adder"
    bl_idname = "VIEW_PT_MainPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Object Adder'
    
    def draw(self, context):
        layout = self.layout
        #layout.scale_y = 1.2
        
        row = layout.row()
        row.label(text= "Add an object", icon= 'OBJECT_ORIGIN')
        row = layout.row()
        row.operator("wm.myop", icon= 'CUBE', text= "Cube")
        row.operator("mesh.primitive_uv_sphere_add", icon= 'SPHERE', text= "Sphere")
        row = layout.row()        
        row = layout.row()    

class Shader_PT_panel(bpy.types.Panel):
    
    bl_label = "Add Shader"
    bl_idname = "Shader_PT_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Object Adder'
    bl_parent_id = 'VIEW_PT_MainPanel'
    bl_options = {'DEFAULT_CLOSED'}

    def draw(self, context):
        layout = self.layout
        layout.operator("addonname.addbasic_operator")



class AddShader(bpy.types.Operator):
    bl_label = "Add Basic Shader"
    bl_idname = "addonname.addbasic_operator"
    
    
    col: bpy.props.FloatVectorProperty(name= "Color", subtype= 'COLOR_GAMMA' , size=4, default= (1,0,0,1))
    
    
    def execute(self, context):
        
        
        material_basic = bpy.data.materials.new(name= "Basic")
        material_basic.use_nodes = True
        
        principled_node = material_basic.node_tree.nodes.get('Principled BSDF')
        principled_node.inputs[7].default_value = 0.08
        
        rgb_node = material_basic.node_tree.nodes.new('ShaderNodeRGB')
        rgb_node.location = (-250, 0)
        rgb_node.outputs[0].default_value = self.col
        
        
        link = material_basic.node_tree.links.new
        link(rgb_node.outputs[0], principled_node.inputs[0])
        
        bpy.context.object.active_material = material_basic

    #Skapar klass för underpanelen
class Options(bpy.types.Panel):
    bl_label = "More Options"
    bl_idname = "VIEW_PT_PanelB"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Object Adder'
    bl_parent_id = 'VIEW_PT_MainPanel'
    bl_options = {'DEFAULT_CLOSED'}
    
    def draw(self, context):
        layout = self.layout
        
        row = layout.row()
        row.label(text= "Select an option")
        row = layout.row()
        row.operator("object.shade_smooth", icon= 'MOD_SMOOTH', text= "Set Smooth Shading")
        row = layout.row()
        row.operator("object.subdivision_set", icon= 'MOD_SUBSURF', text= "Add Subsurf")
        row = layout.row()
        row.operator("object.modifier_add", icon= 'MODIFIER')


        
    #Skapar klass för pop-up menyn där namn och scale kan väljas
class AddCube(bpy.types.Operator):
    """Open the Add Cube Dialog box"""
    bl_label = "Add Cube Dialog Box"
    bl_idname = "wm.myop"
    #Sätter default scale
    text: bpy.props.StringProperty(name= "Enter Name", default= "")
    scale: bpy.props.FloatVectorProperty(name= "Scale:", default= (1,1,1))
    
    def execute(self, context):
        
        t = self.text
        s = self.scale
        
        bpy.ops.mesh.primitive_cube_add()
        obj = bpy.context.object
        obj.name = t
        obj.scale[0] = s[0] 
        obj.scale[1] = s[1] 
        obj.scale[2] = s[2]
         
        
        return {'FINISHED'}
    
    def invoke(self, context, event):
        
        return context.window_manager.invoke_props_dialog(self)
        



    #Registrering av classes      
def register():
    bpy.utils.register_class(MainPanel)
    bpy.utils.register_class(Shader_PT_panel)
    bpy.utils.register_class(AddShader)
    bpy.utils.register_class(Options)
    bpy.utils.register_class(AddCube)
    
    

    #Avregistering av klasser   
def unregister():
    bpy.utils.unregister_class(MainPanel)
    bpy.utils.unregister_class(Shader_PT_panel)
    bpy.utils.unregister_class(AddShader)
    bpy.utils.unregister_class(Options)
    bpy.utils.unregister_class(AddCube)
    
    
    #Säkerhetskodning för att scriptet inte ska köras oavsiktligt
if __name__ == "__main__":
    register()

First up: I’ve never written a Blender addon and, frankly, have yet to
get to grips with Blender itself.

That said, the message above says that some function or method in your
addon is returning None when it should be returning a Python set,
presumably of objects or properties etc. I say “properties” because you
say it fires when you try to choose a colour.

I’ve glanced at this:
https://docs.blender.org/manual/en/latest/editors/preferences/addons.html
but it seems to say little about actually writing addons.

Is there a good page about writing addons and what is required?

Is there a fuller traceback associated with that error above?

Regarding the None: all Python functions return a value. You can
return a specific value with a return statement:

 return something

but if you do not, and control just falls off the end of a function,
there is an implicit:

 return None

and the function returns None, a sentinel value widely sued in Python
to mean “no meaningful value”.

I would assume that some method below which should return a set in
fact has no return value. In normal Python environments you get a
traceback with exceptions like your error message above showing not just
the line where the exception occurred, but also the lines in the code
which called it.

Cheers,
Cameron Simpson cs@cskk.id.au

I’m guessing that it’s complaining that the execute method of AddShader is (implicitly) returning None, because the execute method of AddCube is explicitly returning {'FINISHED'}, which is a set.

2 Likes

Yes, the AddShader class needs to have return{‘FINISHED’} and def invoke etc at the end.