Script to select empties with no children, other than empties?

I’m doing some cleanup work from CAD. In reparenting things to reduce parts, I end up with lots of empties parented to empties. But Occasionally I lose one or two objects within that mess. So lots of manual deleting.

I’d like to actually delete them, but I’m not sure if there’s a way to check to see if they are in use another way. For example, I sometimes create an empty and parent it to an object to mirror around. Does blender see that as a child in any way? It’s more like a cousin? lol

In my case it would be easy enough to avoid deleting those if I only run it on selection. Those are always going to be a “finished” section of the file, so will be in a collection that I can just turn off.

Anyway, just wanted to see if it’s even a reasonable script to create before even adding it to my “learn to script” to-do list. I’ve only half written a couple. They work, but they definitely aren’t finished. So at least I’m getting there.

Sounds like you are on the right track.

It can be tedious to find all of the “if this, then that” possibilities.

Keep trying until you get tired of it and say “All right…, F**K THIS! Never mind!”

Or… there could come a moment where you throw your fists in the air and say “YES!”

1 Like

a child is an object that is hierarchically parented to another object, so yes- blender would see it as a child. Does it matter? No. When you delete an object Blender does not care what you’re using it for, it’s gone- there is no way to ‘protect’ an object from deletion via bpy.data.objects.remove(). That said, If you want to script a solution to your problem it’s 100% possible, but since it would use recursion, it could be a more difficult thing to wrap your head around depending on your skill level with Python.

Since checking for hierarchy membership is pretty easy (assuming you’re comfortable with recursion), the only difficult part is knowing whether an object is being used by a modifier. One strategy would be to create a list of all objects that are being used as a target object by a modifier. This example is for modifiers, but a similar strategy could also be used to test for constraints, etc.

import bpy

def get_modifier_objects(mod):
    if not isinstance(mod, bpy.types.Modifier):
        raise TypeError

    mod_objects = []
    for a in dir(mod):
        val = getattr(mod, a)
        if isinstance(val, bpy.types.Object):         
            mod_objects.append(val)

    return mod_objects
    
    
modifier_objects = []
for o in bpy.data.objects:
    try:
        for m in o.modifiers:
            modifier_objects.extend(get_modifier_objects(m))
    except AttributeError:
        # not all objects use modifiers, skip it.
        pass
    
# remove duplicates
modifier_objects = set(modifier_objects)

print("The following objects are being used as modifier targets:")
print([o.name for o in modifier_objects])

I think I see what you’re getting at. I have been learning as I go, and am Not very far along. I do best learning when whatever I’m doing is immediately useful to me, or at Least so that I understand what is being done while doing it. Most people, unfortunately, end up teaching like this:
“we’re going to make an add-on”
“So type this, now this, now this, I’ll name mine this, type this…and Done.”
Well, great, you taught me typing tutor. AND since they change a Little bit of syntax for every single update, mine doesn’t work because You typed = and it Now needs to be : so thanks for that. lol
And straight up learning python? Well, it never seems immediately applicable to something, and they use words I don’t understand in written documentation so I have to search for that, then the definition is one of those stupid definitions that would be like: Recursive is characterized by recurrence. OH, Well thanks for That! I know what that is, just using that as an example of why I find learning it difficult.

Your script is clear though. I haven’t learned much yet though. I have Huge problems understanding context, and don’t Really understand “def” yet, just to let you know how much of a beginner. It’s easy to look up if, for, try, except. But some of the other things are harder to learn about, like syntax for something. For instance you’ve got mod_objects = []. A quick search tells me that you’re doing that to define the variable as an empty list? But I will Not be surprised if that isn’t correct because it looks like you can Also do that like: mod_objects = list() ?