append entire scene python to current scene

ive been googling a bit already regarding this question.
Ive seen the bpy.ops.wm.append() method as well as the bpy.data.libraries.load() method, but still cant figure this out.

How can i merge an external file 's content into my current scene via python?

the examples ive found do need to specify the “category”/“group” of the file so i did something like this:

with bpy.data.libraries.load(myfile) as (data_from, data_to):
    for section in dir(data_from):
        files = []
        print('***** Section ' + section + ' ******')
        for name in getattr(data_from, section):
            files.append({'name' : name})
            print(name)
        #data_to_category = getattr(data_to, section)
        #data_from_category = getattr(data_from, section)
        #data_to_category = data_from_category
        
        if files:
            bpy.ops.wm.append(directory=myfile+"\\" + section.capitalize() + "\\", files=files)
            #bpy.ops.wm.append(directory=myfile+'\\*\\', files=files)
            pass

although this makes blender crash!

Im starting from this point:

with bpy.data.libraries.load(myfile) as (data_from, data_to):
    files = []
    for obj in data_from.objects:
        files.append({'name' : obj})
    bpy.ops.wm.append(directory=myfile+'\\Object\\', files=files)

This works and brings all objects from the myfile blend file into my current new scene.

How can i bring everything without the need to specify a category like “Object”? Is there no other way than go category by category performing same actions? what if there are custom categories defined in the blend file by the another user? Im looking for something like a wildcard something to be able to do:

bpy.ops.wm.append(directory=myfile+'\\*\\', files= files

for example.

Another thing that would suit me for good is a way to retrieve all category names in a blend file. Ive inspected a little bit the “data_from” object but with no luck for this. This way, i would be able to copy all objects category by category.

This works (taken from the api docs)


import bpy

FILEPATH = '/home/januz/tmp/append_test.blend'

with bpy.data.libraries.load(FILEPATH) as (data_from, data_to):
    for attr in dir(data_to):
        setattr(data_to, attr, getattr(data_from, attr))

This snippet will import all scenes and data. Not sure what you mean by category, but I understand data_from should support any blender data type: meshes, materials, objects, groups, scenes, etc.

Also keep in mind Blender’s dependency model, if you append something it will pull it’s dependencies. For instance, appending an object will also append its material. You can append a scene and it will pull all objects linked to it, and all data linked to those objects (materials, animations, etc.).

Hi, thanks for answering, but this i already tried and the objects dont appear in the scene viewport… do i need to update something?

by category i mean what blender interprets as the “Object” or “Material” folder in a blend file when you try to append something using the gui

That’s odd. Did you check the scenes list? Didn’t it add the scenes from the blend file you’re appending?

Yeah this should work withload() I think

That’s odd. Did you check the scenes list? Didn’t it add the scenes from the blend file you’re appending?

it doesnt work, i think you are just assigning a list to another list in python but that alone doesnt make the scene update itself in the viewport with the objects.

you need to do something with the bpy.ops.wm.append method, but dont know how to use it without specifiying a category…

When the context manager ends, it takes the contents of data_to and appends them. There’s no need to manually call the op.

I ran the script again withprint('attr is', attr). These are the data types you get:

attr is actions
attr is armatures
attr is brushes
attr is cache_files
attr is cameras
attr is curves
attr is fonts
attr is grease_pencil
attr is groups
attr is images
attr is ipos
attr is lamps
attr is lattices
attr is linestyles
attr is masks
attr is materials
attr is meshes
attr is metaballs
attr is movieclips
attr is node_groups
attr is objects
attr is paint_curves
attr is palettes
attr is particles
attr is scenes
attr is sounds
attr is speakers
attr is texts
attr is textures
attr is worlds

take one of the datatypes you posted, for example objects:
This works:

with bpy.data.libraries.load(myfile) as (data_from, data_to):
    files = []
    for obj in data_from.objects:
        files.append({'name' : obj})
    bpy.ops.wm.append(directory=myfile+'\\Object\\', files=files)

This piece of code appends successfully the objects to the scene, whereas doing this doesnt:

with bpy.data.libraries.load(FILEPATH) as (data_from, data_to):
    for attr in dir(data_to):
        setattr(data_to, attr, getattr(data_from, attr))

Do the test yourself! by the way, im on blender 2.79

I have tested that code and it works me. It appends the scene with everything in it.

One thing to notice when working with load() and objects is that it doesn’t link them to any scene. If you go to the outliner and set it to datablocks, you’ll find the objects there. They have been appended to the blend file’s data, they are just not linked to any scene.

I’ve tweaked the snippet to append objects (only) and link them to the current scene:


import bpy


FILEPATH = '/home/januz/tmp/appen_test.blend'

with bpy.data.libraries.load(FILEPATH) as (data_from, data_to):
    data_to.objects = [name for name in data_from.objects]
    print('These are the objs: ', data_to.objects)

# Objects have to be linked to show up in a scene
for obj in data_to.objects:
    bpy.context.scene.objects.link(obj)   

this is a very similar behaviour to using append files {‘name’:obj} after iterating again through data_from.objects as in the example i provided earlier. Two questions:

  1. what’s the difference then between using the first method:

    with bpy.data.libraries.load(myfile) as (data_from, data_to):
    files = []
    for obj in data_from.objects:
    files.append({‘name’ : obj})
    bpy.ops.wm.append(directory=myfile+’\Object\’, files=files)

and yours:

with bpy.data.libraries.load(FILEPATH) as (data_from, data_to):
    data_to.objects = [name for name in data_from.objects]
    print('These are the objs: ', data_to.objects)

# Objects have to be linked to show up in a scene
for obj in data_to.objects:
    bpy.context.scene.objects.link(obj) 

I guess what im asking is the difference between appending and linking in blender. (im very new to blender)

  1. this linking step, is it only mandatory when treating with objects? or do we need to do it with all datatypes to be shown in the scene?

In the context of files:
Appending: Make a full copy of the data from another file
Linking: Create a reference to data in another file

In the case of the snippet we’re talking about linking to a scene which is different. It means creating a reference to the object in the scene. Basically telling Blender “this object should be in this scene”.

The load() context manager takes care of appending the objects you put in data_to once you exit the with block (copying them from the blend file) but it doesn’t link them to any scene, so you have to manually link them afterwards. The append operator does both the appending and linking to the currently used scene.

Yes, but you also have to link or use the other datatypes if you want to see them. For instance if you append a world you have to set it as the world of some scene (scene.world = my_world). Materials, animations, etc. are usually linked to objects, so if you append an object those datablocks will also be appended and linked to the object. Scenes are at the top of the hierarchy so they don’t have to be linked.

It goes something like this:
Scene -> Objects -> Materials/Animations/etc

Lets say you have an object with a material and diffuse texture, you only need to append and link the object and everything else gets pulled and linked for you.

Object -> Material -> Texture -> Image

Check out the manual for more info on Blender’s data system.