0
$\begingroup$

I wrote this simple python script for Blender 2.69, which creates a new operator. The operator is supposed to change the energy for four lamps in the scene (essentially switching them off and on again). However, while the script runs fine and creates the operator itself, when I select the operator, it has no effect on the lamps' energy.

Entire script:

import bpy


def main(context):
    for ob in context.scene.objects:
        print(ob)


class LightsOperator(bpy.types.Operator):

    bl_idname = "object.lights_operator"
    bl_label = "Headlight Operator"

@classmethod
def poll(cls, context):
    return context.active_object is not None

def execute(self, context):

    if bpy.data.objects['headlight1'].energy==0.0:
        bpy.data.objects['headlight1'].energy = 0.8
    else:
        bpy.data.objects['headlight1'].energy = 0.0


    if bpy.data.objects['headlight2'].energy==0.0:
        bpy.data.objects['headlight2'].energy = 0.8
    else:
        bpy.data.objects['headlight2'].energy = 0.0

    if bpy.data.objects['headlight3'].energy==0.0:
        bpy.data.objects['headlight3'].energy = 0.8
    else:
        bpy.data.objects['headlight3'].energy = 0.0

    if bpy.data.objects['headlight4'].energy==0.0:
        bpy.data.objects['headlight4'].energy = 0.8
    else:
        bpy.data.objects['headlight4'].energy = 0.0

def register():
    bpy.utils.register_class(LightsOperator)


def unregister():
    bpy.utils.unregister_class(LightsOperator)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.object.lights_operator()
$\endgroup$
1
  • $\begingroup$ Could it be that the poll and execute methods are not inside the class? Make sure that you indent them correctly $\endgroup$ – WorldSEnder May 23 '14 at 17:12
2
$\begingroup$

Here is a variation of the script that works on all lamp objects with their name (ob.data.name! ) starting with "headlight" (case insensitive):

import bpy

class LightsOperator(bpy.types.Operator):
    bl_idname = "object.lights_operator"
    bl_label = "Headlight Operator"

    def execute(self, context):

        for ob in context.scene.objects:
            if not ob.type == 'LAMP':
                continue
            lamp = ob.data
            if lamp.name.lower().startswith("headlight"):
                lamp.energy = 0.0 if lamp.energy >= 0.8 else 0.8

        return {'FINISHED'}

def register():
    bpy.utils.register_class(LightsOperator)

def unregister():
    bpy.utils.unregister_class(LightsOperator)

if __name__ == "__main__":
    register()

    # test call
    bpy.ops.object.lights_operator()

Note that it toggles the lights between 0.0 and 0.8, no matter what the initial value is. If you want to toggle only those with a specific energy, keep rounding errors in mind - it isn't really 0.8 unless you round(lamp.energy, 1):

>>> lamp.energy = 0.8

>>> lamp.energy == 0.8
False

>>> lamp.energy
0.800000011920929

>>> round(lamp.energy, 1)
0.8
$\endgroup$
0
$\begingroup$

Objects in scripting (bpy.data.objects) are not the same as the Objects you add with ShiftA.

Every scene holds a list (bpy_prop_collection) of objects. Now this is an abstract object that holds information that every object type (Mesh, Lamp, Armature) share - like position in worldspace, modifiers, etc. Here was your error.

Instead of calling bpy.data.objects[name].energy, the correct call is bpy.data.objects[name].data.energy.

Here is an improved version of the script that acts on the currently selected object (as the poll()-method suggests). Call it for every object by first setting context.scene.objects.active and then calling the operator with bpy.ops.object.lights_operator:

import bpy

def main(context):
    for ob in context.scene.objects:
        print(ob)

class LightsOperator(bpy.types.Operator):
    """Doc"""
    bl_idname = "object.lights_operator"
    bl_label = "Headlight Operator"

    # these two methods belong to the class, not global space
    @classmethod
    def poll(cls, context):
        # can also use context.object instead of context.active_object
        return context.object is not None

    def execute(self, context):
        # get the object
        obj = context.object

        # check if it is a lamp
        if not obj.type == 'LAMP':
            return {'CANCELLED'}

        # now this is an abstraction by Blender. Every scene
        # has objects. Those objects contain the data (mesh,
        # curve, and LAMPS). So to access the data of the
        # lamp we do
        lamp = obj.data

        if lamp.energy == 0:
            lamp.energy = 0.8
        else:
            lamp.energy = 0

        return {'FINISHED'}

def register():
    bpy.utils.register_class(LightsOperator)

def unregister():
    bpy.utils.unregister_class(LightsOperator)

if __name__ == "__main__":
    register()

    # test call
    bpy.ops.object.lights_operator()
$\endgroup$
6
  • $\begingroup$ The original indentation was just a result of copy+pasting. But to just make sure, I copy+pasted your indented script, and it just returns a "Python script fail". Typing directly into the console gives me a whole bunch of "unexpected indent"s. $\endgroup$ – Ollie May 23 '14 at 17:28
  • $\begingroup$ It may give a "Python script fail" if the following objects are not in the current scene: 'headlight1', 'headlight2', 'headlight3', 'headlight4'. Check if there are four lamps with exactly thos names (yes capitalization matters). I know that it gives an error when run in the console. I'll update so that you can run it from console. $\endgroup$ – WorldSEnder May 23 '14 at 17:34
  • $\begingroup$ Yep those exact names are definitely there :) $\endgroup$ – Ollie May 23 '14 at 17:38
  • $\begingroup$ Okay the script is updated and should now work as described above $\endgroup$ – WorldSEnder May 23 '14 at 18:03
  • $\begingroup$ Thanks for your help but the new script still doesn't work. :( $\endgroup$ – Ollie May 24 '14 at 10:08

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.