I tried to make a multiple file add-on using _ init _.py file I have two files from which I am trying to import operator and panel first file is material_operator.py in which I have defined an operator and second file is panel.py and in this, I have created a panel for the add-on. so, totally 3 files-

  1. _ init _.py
  2. material_operator.py
  3. panel.py

so when I install the add-on it is successfully installed and works properly, but the problem is when I open console it gives the following error -

fake_module: addon missing 'bl_info' gives bad performance!:
'C:\\Users\\ADMIN\\AppData\\Roaming\\Blender Foundation\\Blender\\2.83\\scripts\\addons\\panels.py' 
fake_module: addon missing 'bl_info' gives bad performance!:
 'C:\\Users\\ADMIN\\AppData\\Roaming\\Blender Foundation\\Blender\\2.83\\scripts\\addons\\shader.py'

my script is as follows -

  1. _ init _.py

    bl_info = {
    "name": "Add Test Material",
    "author": "Rakesh Choudhary",
    "version": (1, 0),
    "blender": (2, 83, 0),
    "location": "View3D > Sidebar > Test Material Node",
    "description": "Click on the 'Test Material' button to add a material to your object.",
    "warning": "",
    "wiki_url": "",
    "category": "3D View"
    import bpy
    from bpy.types import (
    from . import material_operator
    from . import panel
    def register():
    def unregister():
    if __name__ == "__main__":
  2. material_operator.py - in this an operator is created in which a material is made

    import bpy
    from bpy.types import (
    class TEST_MATERIAL_OT_add_material(Operator):
        bl_idname = "test_material.add_material"
        bl_label = "Add Test Material"
        bl_description = "This button will add a material to your object"
        def execute(self, context):
            return {'FINISHED'}
        def create_material(self):
            test_shader_mat = bpy.data.materials.new("TestMat")
            mesh = bpy.context.object.data
            bpy.context.object.active_material.use_nodes = True
            for mat in bpy.data.materials:
                if "TestMat" in mat.name:
                    nodes = mat.node_tree.nodes
                    for node in nodes:
                        if node.type != 'OUTPUT_MATERIAL':  # skip the material output node as we'll need it later
            # Creating Node Group Test_Material
            group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")
            # Creating Group Input
            group.inputs.new("NodeSocketColor", "Diffuse Color")
            group.inputs.new("NodeSocketColor", "Glossy Color")
            group.inputs.new("NodeSocketFloat", "Glossyness")
            input_node = group.nodes.new("NodeGroupInput")
            input_node.location = (-800, 0)
            # Creating Group Output Node
            group.outputs.new("NodeSocketShader", "Diffuse Color")
            group.outputs.new("NodeSocketShader", "Glossy Color")
            group.outputs.new("NodeSocketShader", "Mix Output")
            output_node = group.nodes.new("NodeGroupOutput")
            output_node.location = (1500, 0)
            # Creating Diffuse Node
            diffuse_node = group.nodes.new(type='ShaderNodeBsdfDiffuse')
            diffuse_node.location = (150, 100)
            # Creating Glossy Node
            glossy_node = group.nodes.new(type='ShaderNodeBsdfGlossy')
            glossy_node.location = (300, 250)
            # Creating Mix Shader Node
            mix_shader_node = group.nodes.new(type='ShaderNodeMixShader')
            mix_shader_node.location = (450, 100)
            #Creating Color Ramp ------------------------------------------------------
            col_ramp = group.nodes.new(type="ShaderNodeValToRGB")
            #col_ramp.name = "col_ramp"
            col_ramp.location = (400, -300)
            col_ramp.color_ramp.elements[0].color = (0,0,0,1)
            col_ramp.color_ramp.elements[1].position = (1.0)
            col_ramp.color_ramp.elements[1].color = (1, 1, 1, 1)
            # Creating Links Between Nodes----------------------------------------------
            group.links.new(diffuse_node.outputs["BSDF"], mix_shader_node.inputs[1])
            group.links.new(glossy_node.outputs["BSDF"], mix_shader_node.inputs[2])
            group.links.new(input_node.outputs["Diffuse Color"], diffuse_node.inputs[0])
            group.links.new(input_node.outputs["Glossy Color"], glossy_node.inputs[0])
            group.links.new(input_node.outputs["Glossyness"], glossy_node.inputs[1])
            group.links.new(output_node.inputs["Diffuse Color"], diffuse_node.outputs[0])
            group.links.new(output_node.inputs["Glossy Color"], glossy_node.outputs[0])
            group.links.new(output_node.inputs["Mix Output"], mix_shader_node.outputs[0])
            group.links.new(col_ramp.outputs["Color"], mix_shader_node.inputs[0])
            # Putting Node Group to the node editor
            tree = bpy.context.object.active_material.node_tree
            group_node = tree.nodes.new("ShaderNodeGroup")
            group_node.node_tree = group
            group_node.location = (-40, 300)
            group_node.use_custom_color = True
            group_node.color = (1, 0.341, 0.034)
            group_node.width = 250
            shader_node_output_material_node = tree.nodes["Material Output"]
            links = tree.links
            links.new(group_node.outputs[0], shader_node_output_material_node.inputs[0])
            #Material ends here------------------------------
    classes = (TEST_MATERIAL_OT_add_material)
    def register():
    def unregister():
    if __name__ == "__main__":
  3. panel.py - this is the file in which panels are created

    import bpy
    from bpy.types import (
    class TEST_MATERIAL_PT_layout_panel(Panel):
        bl_label = "Test Material Node"
        bl_category = "Test Material"
        bl_space_type = "VIEW_3D"
        bl_region_type = "UI"
        def draw(self, context):
            layout = self.layout
            layout.operator("test_material.add_material", icon='IMPORT')
    def register():
    def unregister():
    if __name__ == "__main__":

Can anyone tell me what I am missing here?

  • 2
    $\begingroup$ Replace: mesh = bpy.context.object.data by mesh = context.object.data, bpy.context.object.active_material.use_nodes = True by context.object.active_material.use_nodes = True and bpy.context.object.active_material.node_tree by context.object.active_material.node_tree... $\endgroup$ – brockmann Jun 26 '20 at 13:11

Multi file addons require their own folder.

The issue you are having is, addons is your addons folder. The error reports that all of your files are there. Having an __init__.py in your addons folder is a bad idea too. An init in a folder tells python to treat it as a module. Fortunately, I believe the devs foresaw this possibility and the folder is not directly import, otherwise you'd snaff up all the addons.

Instead if your addon is to be called my_addon and has another file foo.py create the structure like so


Having erroneously placed all files in the addons folder,it sees panels.py as an addon to install, which is missing the bl_info dictionary. -> The error.


Recently answered giving a run down on a multi file addon here Trying to make a menu using multiple modules

  • 1
    $\begingroup$ @Rakeshchoudhary Addon is looking good. A small suggestion. If using context in an operator method go for def create_material(self, context) and pass context as you would calling other methods like invoke, execute, and draw eg with self.create_material(context) At the time being this does not alter the result, as AFAIK the context passed and bpy.context are always same, even if context is overridden. If in the future this is changed it could result in context passed in operators with overridden context may not match "actual context", then it would be a difficult issue to debug. $\endgroup$ – batFINGER Jun 26 '20 at 10:05

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.