6

I want to add a lamp the current scene using python on startup. I do not want to change the default scene.

Here is the code that I am using:

import bpy

bpy.ops.object.lamp_add(type='POINT', view_align=False, location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))

It adds a point lamp at origin. Like this answer suggests: I have saved this file in scripts/startup as a add_lamp.py

How ever when I start blender nothing has changed. I see no lamps added.

Vader
  • 14,680
  • 16
  • 74
  • 110
  • To call an operator from an addon, this solution worked for me: https://blender.stackexchange.com/questions/8702/attributeerror-restrictdata-object-has-no-attribute-filepath – NumesSanguis Mar 14 '21 at 07:07

2 Answers2

10

Background Info...

Blender intentionally prevents you from manipulating the scene at startup, this is because it is rarely useful and you end up running into issues - like loading a blend file immediately overwrite any changes you have made.

Other data such as the user preferences can be manipulated since this persists across different blend files.

1. Explicit Execution

So, if you want to do this, you can use a command line argument to run a text block in your startup.blend:

blender --python-text lamp.py

Or you can reference a path directly:

blender --python /path/to/lamp.py

This way you can control if the script runs before or after loading a blend file.

# add the lamp to any blend you open
blender example.blend --python-text lamp.py

# add the lamp, then overwrite it (not useful in this case)
blender --python-text lamp.py example.blend

The main drawback for this is it needs to be added to some startup script or launcher, or manually entered into the commandline each time you start blender.


2. Using Callbacks

Heres an example of a script you can place in startup/ which adds a handler that can manipulate the scene how you like.

import bpy

def load_handler(dummy):
    bpy.ops.object.lamp_add(type='POINT', view_align=False, location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))

bpy.app.handlers.load_post.append(load_handler)

This is another example which keeps the handler active but only executes on new files.

import bpy
from bpy.app.handlers import persistent

@persistent
def load_handler(dummy):

    # only apply to startup
    if not bpy.data.filepath:
        return

    bpy.ops.object.lamp_add(type='POINT', view_align=False, location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))

bpy.app.handlers.load_post.append(load_handler)

This may seem overkill for such a simple task, but when you consider it gives you the ability to execute code on any newly loaded file, its quite flexible.

ideasman42
  • 47,387
  • 10
  • 141
  • 223
  • I want to achieve this with both pieces of code in method 2. I also tried using blender --python-text lamp.py. But it did not work. – Vader Mar 02 '14 at 14:41
  • --python-text relies on the textblock being available in bpy.data.texts, it should work as long as the text's available. – ideasman42 Mar 02 '14 at 15:04
  • Why did neither method for the callacks work? – Vader Mar 02 '14 at 15:07
  • You ask why something failed without providing any info, Im not even sure what neither method for the callacks means. If something fails you need to provide a way to redo the failure, it could even be a bug, though in this case I doubt it since the features have been used/tested fairly well. – ideasman42 Mar 03 '14 at 06:53
2

You're probably using 2.7, the console now prints:

Warning! 'C:\Users\user\blender-2.70-testbuild1-win64\2.69\scripts\startup\lamps.py' 
has no register function, this is now a requirement for registerable scripts

You would need to add a register function to you script.

I tried this:

import bpy

def register():
    print("add")

this works, but your operator invocation leads to:

Traceback (most recent call last):
  File "C:\Users\user\blender-2.70-testbuild1-win64\2.69\scripts\modules\bpy\utils.py", line 160, in register_module_call
    register()
  File "C:\Users\user\blender-2.70-testbuild1-win64\2.69\scripts\startup\lamps.py", line 5, in register
    bpy.ops.objects.lamp_add(type='POINT', view_align=False, location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0),layers=(True, False,
 False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
  File "C:\Users\user\blender-2.70-testbuild1-win64\2.69\scripts\modules\bpy\ops.py", line 182, in __call__
    BPyOpsSubModOp._scene_update(context)
  File "C:\Users\user\blender-2.70-testbuild1-win64\2.69\scripts\modules\bpy\ops.py", line 148, in _scene_update
    scene = context.scene
AttributeError: '_RestrictContext' object has no attribute 'scene'
stacker
  • 38,549
  • 31
  • 141
  • 243