1
$\begingroup$

I want to duplicate an instance collection, apply/make instances real, run some code on the objects, then delete them. The problem is the Empty object isn't selected after making the instance real, so when I delete selected it stays behind. I've tried selecting it and/or deleting it with code but I get 'NoneType' has no attribute 'name' and 'NoneType' has no attribute 'select_set', 'delete', etc. I don't understand why I can't do anything with an Empty. It has a name, but I can't get its name because it has no attributes.

My question - how can I delete a specific empty with code?

$\endgroup$
2
  • 2
    $\begingroup$ Hello, could you post sample of your code (specifically the part where you select and delete the object) $\endgroup$
    – Gorgious
    Jul 5, 2021 at 21:12
  • $\begingroup$ look here: blender.stackexchange.com/questions/109238/…. This should help you. Just delete the "if" $\endgroup$
    – Chris
    Jul 6, 2021 at 6:20

2 Answers 2

3
$\begingroup$

Removing collection instances only.

If we add a collection instance of "Collection 1" and look at the new object in python console

>>> C.object
bpy.data.objects['Collection 1.001']

>>> C.object.type.startswith('EMPTY')
True

>>> C.object.is_instancer
True

>>> C.object.instance_type
'COLLECTION'

>>> C.object.instance_collection is D.collections['Collection 1']
True

Similar to All empties with no children code to find only collection instances of the context collection in the scene. (can instead use e.data is None in this instance)

A quick test is to simply check the collection name given to the empty (will start with it)

ic_empties = [e for e in scene.objects if not e.data and e.name.startswith(colname)]

Example

I want to duplicate an instance collection, apply/make instances real, run some code on the objects, then delete them.

Added as an example

  • Adds 10 copies of a collection instance to scene base collection and randomly locates them
  • finds all empty collection instances of "Collection 1", makes them real, then removes their empty.

Test script.

import bpy
from random import random

context = bpy.context
colname = "Collection 1"
copies = 10 # make 10 collection instances of colname
coll = bpy.data.collections.get(colname)
scene = context.scene

bpy.ops.object.collection_instance_add(collection=colname)

for i in range(copies-1):
    cp = context.object.copy()
    cp.location = (10 * random(), 10 * random(), 10 * random())
    scene.collection.objects.link(cp)

# could keep references above, use name, but will find again by way of example
ic_empties = [
        e for e in scene.objects
        if e.type.startswith('EMPTY') 
        and e.is_instancer
        and e.instance_type == 'COLLECTION'
        and e.instance_collection is coll
        ]



# make them all real
bpy.ops.object.duplicates_make_real(
        {"selected_objects" : ic_empties},
        )
# remove the empties.        
while ic_empties:
    bpy.data.objects.remove(ic_empties.pop())

The "real" objects remain selected after running the script

$\endgroup$
2
  • $\begingroup$ Let's deal with an elephant in the room, why .type.startswith('EMPTY') and not .type == 'EMPTY'? Expecting some custom extension types? $\endgroup$ Jul 6, 2021 at 9:05
  • 1
    $\begingroup$ It's suggested as quicker in blender best practices (startswith vs equality) , hoping against other types starting with empty. Sometimes I forget I've used it instead. $\endgroup$
    – batFINGER
    Jul 6, 2021 at 9:08
3
$\begingroup$

you can use this script:

import bpy

for e in [e for e in bpy.data.objects if not e.data]:
    bpy.data.objects.remove(e, do_unlink=True)
$\endgroup$
3
  • $\begingroup$ @MarkusvonBroady there are instances (UVMaps comes to mind blender.stackexchange.com/questions/191920/… ) where iterating over the list you are removing from does not work as expected, hence usage of the while construct that you have edited out. $\endgroup$
    – batFINGER
    Jul 6, 2021 at 11:02
  • $\begingroup$ @batFINGER I was thinking about that, that's why I'm using a list comprehension, not a generator expression there (or just for e in bpy.data.objects and if not e.data: continue on the next line), so the list is still generated before the loop starts. $\endgroup$ Jul 6, 2021 at 12:39
  • $\begingroup$ I mean if e.data: continue or if not e.data: # remove $\endgroup$ Jul 6, 2021 at 12:46

You must log in to answer this question.

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