KeyError: 'bpy_prop_collection[key]: key not found' ?

hey guys,

so we have a setup for our python exam in computer science.

we provide a simple ui with generating predefined lamp setups (portrait etc) and then some ui elements to control these lamps.

it all works fine until a lamp is renamed - then this happens:

KeyError: ‘bpy_prop_collection[key]: key “test” not found’

here are some code snippets:

class SwitchOffAllLampsOperator(bpy.types.Operator):    bl_idname = "object.switchoffalllamps_operator"
    bl_label = "Simple Lamp Switch Off Operator"
    oldLampStrength = 0
    
    def execute(self, context):
        currentLampStrength = int(GetLampStrength(context.object))

then calls

def GetLampStrength(lamp):    print(lamp)
    return bpy.data.lamps[lamp.name].node_tree.nodes["Emission"].inputs[1].default_value

and this is where the exception is thrown.

Here’s the whole code, i dont see any “spoiler” possibilities so ill just put it here:

import bpy

from bpy.types import Menu, Panel, UIList


class ViewLightningPanel():
    # where the new panel will be accessable
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    
# the new panel
class LampAdjustPanel(ViewLightningPanel, Panel):
    bl_idname = "panel_lampadjust"
    bl_label = "Lamp Adjustment"
    bl_context = "objectmode"
    bl_category = "LMD"
    
    # draw a new button, call operator on click
    def draw(self, context):
        layout = self.layout
        col = layout.column(align = True)
        layout.operator("object.lamp_selection_operator", text = "Select All Lamps")
        layout.operator("object.switchoffalllamps_operator", text = "Switch Lamps On / Off")
        layout.operator("brightness.operator", text = "Change Luminosity")
        layout.operator("colour.operator", text = "Change Colour")
        
class ColourOperator(bpy.types.Operator):
    bl_idname = "colour.operator"
    bl_label = "Set Colour in Red, Green, Blue"
    redValue = bpy.props.IntProperty(name="Red", description ="Red Proportion", max = 255, min = 0)
    greenValue = bpy.props.IntProperty(name="Green", description ="Green Proportion", max = 255, min = 0)
    blueValue = bpy.props.IntProperty(name="Blue", description ="Blue Proportion", max = 255, min = 0)
    
    def execute(self,context):
        SetColour(int(self.redValue), int(self.greenValue), int(self.blueValue))
        return{'FINISHED'}
    def invoke(self, context, event):
        wm = context.window_manager
        return wm.invoke_props_dialog(self)
    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.prop(self,"redValue")
        col.prop(self,"greenValue")
        col.prop(self,"blueValue")        
        
class BrightnessOperator(bpy.types.Operator):
    bl_idname = "brightness.operator"
    bl_label = "Set Luminosity"
    defaultValue = 0
    brightnessValue = bpy.props.IntProperty(name="Luminosity", description ="the actual brightness", min = 10, default = defaultValue) #default remains 0 ? why?
    
    def execute(self,context):
        self.report({'INFO'}, str(self.brightnessValue))
        SetLampStrength(context, int(self.brightnessValue))
        return{'FINISHED'}
    def invoke(self,context,event):
        wm = context.window_manager
        BrightnessOperator.defaultValue = int(GetLampStrength(context.object)) #proof that the value is set correctly
        print (BrightnessOperator.defaultValue) # print proof, still - doesnt work.
        return wm.invoke_props_dialog(self)
    def draw(self, context):
        print(BrightnessOperator.brightnessValue)
        layout = self.layout
        col = layout.column()
        col.prop(self,"brightnessValue")


# operator for button
class SelectAllLampsOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.lamp_selection_operator"
    bl_label = "Simple Lamp Selection Operator"


    def execute(self, context):
        SelectAllLamps(context)
        return {'FINISHED'}
    
class SwitchOffAllLampsOperator(bpy.types.Operator):
    bl_idname = "object.switchoffalllamps_operator"
    bl_label = "Simple Lamp Switch Off Operator"
    oldLampStrength = 0
    
    def execute(self, context):
        currentLampStrength = int(GetLampStrength(context.object))
                
        if currentLampStrength != 0:
            print("not dark!")
            SwitchOffAllLampsOperator.oldLampStrength = currentLampStrength
            SetLampStrength(context, 0)
        
        elif currentLampStrength == 0:
            print("dark!")
            SetLampStrength(context, SwitchOffAllLampsOperator.oldLampStrength)
                                
        return {'FINISHED'}
    
    
    
def SetColour(red, green, blue):
    print(red, green, blue)
    sce = bpy.context.scene
    for object in sce.objects:
        if object.type == "LAMP":
            bpy.data.lamps[object.name].node_tree.nodes["Emission"].inputs[0].default_value = (red, green, blue, 1)


        
def SetLampStrength(context, lampStrength):
    helligkeit = lampStrength
    sce = bpy.context.scene
    for object in sce.objects:
        if object.type == "LAMP":
            bpy.data.lamps[object.name].node_tree.nodes["Emission"].inputs[1].default_value = helligkeit


def GetLampStrength(lamp):
    print(lamp)
    return bpy.data.lamps[lamp.name].node_tree.nodes["Emission"].inputs[1].default_value


    
# function for operator
def SelectAllLamps(context):
    sce = bpy.context.scene
    for object in sce.objects:
        if object.type != "LAMP":
            object.select = False 
        else:
            object.select = True
        
        
        
def register():
    #bpy.utils.register_class(LampAdjustPanel)
    #bpy.utils.register_class(SelectAllLampsOperator)
    #bpy.utils.register_class(SwitchOffAllLampsOperator)
    #bpy.utils.register_class(BrightnessOperator)
    #bpy.utils.register_class(ColourOperator)
    bpy.utils.register_module(__name__)




def unregister():
    #bpy.utils.unregister_class(LampAdjustPanel)
    #bpy.utils.unregister_class(SelectAllLampsOperator)
    #bpy.utils.unregister_class(SwitchOffAllLampsOperator)
    #bpy.utils.unregister_class(BrightnessOperator)
    #bpy.utils.unregister_class(ColourOperator)
    bpy.utils.unregister_module(__name__)




if __name__ == "__main__":
    register()
    # seems to be needed (?)
    # bpy.ops.object.simple_operator()
    

thanks in advance for any help :slight_smile:

You have to write code for the Blender Python API in an exam? That seems like an odd choice, many parts of the API have little or no documentation.

As to the code, I’m not overly familiar with how lamp data is accessed in the API, but I spotted a few problems.

  1. The way your code is currently written, it doesn’t prevent functions like “GetLampStrength” from being called on objects that aren’t lamps. “context.object” can be any object (and can also be None if nothing is selected or if there’s an empty scene). So if a lamp object isn’t selected, the “bpy_prop_collection” stored in “bpy.data.lamps” gets searched for a non-lamp name, that is what is giving you the “KeyError key not found” error message.

  2. I would also recommend adding a check to make sure the lamps node_tree is not empty before trying to access data with “node_tree.nodes”. Something like:

if bpy.data.lamps[object.name].node_tree is not None:
  1. Not a bug, but a tip. When using print statements for debugging, I find it helpful to add a short description in front of the value being printed out. I usually just copy and paste the value name as a string value:
# example, instead of
print(lamp)

# I would use
print("lamp:", lamp)

It makes it easier to spot when the value printed out is different than what is expected:

lamp: <bpy_struct, Object("Cube")>