2
$\begingroup$

When using bpy.ops.wm.append() to bring in objects from another .blend file, if the newly imported objects have name collisions with existing objects in the scene, Blender will rename the colliding named objects. How to get the list of just imported objects, so their potentially altered names can be known?

Alternatively, I can easily pre-determine if there will be name collisions before use of bpy.ops.wm.append(). Is there a way to tell this operator to use a list of alternative names when adding the appended objects to the scene?

$\endgroup$

1 Answer 1

3
$\begingroup$

Determining if there is a conflict

There is not a way to tell bpy.ops.wm.append to do name replacement.

One way to call append only appends one object at a time and it will attempt to name it the same as the filename argument. You could test before the call if you already have an object by that name, or after the call if you have multiple objects with that as the short name.

Here's an example, drawn from an operator that appends all of the materials from a file. You could adapt it easily, I think

    with bpy.data.libraries.load(str(file_path)) as (data_from, data_to):
        data_to.materials = data_from.materials
    for linked_material in data_to.materials:
        object_name = linked_material.name
        # Place code to check if there is already a material named
        # object_name here.
        bpy.ops.wm.append(
        filepath=str(file_path / inner_path / object_name),
        directory=str(file_path / inner_path),
        filename=object_name
    )

In this example, one way to do the test might be similar to this untested code:

try:
    match = bpy.data.materials[object_name]
    # There is a conflict do what you need to
except KeyError:
    # There is no error.  pass is probably OK
    pass

Obviously this only works for materials and you need to substitute the proper object type, ie objects everywhere materials appears above.

determining the new objects:

old_set = set(bpy.data.materials[:])
# Call bpy.ops.wm.append as needed
new_set = set(bpy.dta.materials[:]) - old_set

This uses Python Set Objects to calculate what objects did not exist before the calls were made. The call to set creates a snapshot of the current state, so calling it before any changes creates a 'before any' snapshot and calling it after creates a 'after all' snapshot. You can add as many objects as you like between the two calls because new_set returns a set consisting of only the new objects.

If you're importing multiple types, ie objects and materials, just make the before, after, and difference calls for each type. You could then create a set consisting of all of the types if you wanted.

$\endgroup$
4
  • $\begingroup$ That last bit of comparing the old set with the new set looks promising. Considering this a bit, it looks like I'll need to import one at a time to make this work as I need it. $\endgroup$ Jul 9, 2022 at 23:59
  • 1
    $\begingroup$ If you use the last bit you don't need to import one at a time. The thing is that the call to set creates a 'before any' and then 'after all' snapshot and new_set is the difference. It'll be a set of all the new objects. I've updated the answer to expand on that. $\endgroup$ Jul 10, 2022 at 0:03
  • $\begingroup$ If the intent is to append 20 objects, and 5 of them have name collision, will using set maintain operation order, or will they be reordered alphabetically or something? That's why I was considering doing the appends one at a time, because doing multiple may not preserve name order in the after set. $\endgroup$ Jul 10, 2022 at 3:31
  • 1
    $\begingroup$ Set doesn't guarantee any ordering at all, so if you need to preserve ordering its not the best approach. $\endgroup$ Jul 10, 2022 at 23:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .