Delete keys error.

I’m deleting keys from multiple objects in a loop.

I’m stepping through the frames within a specific range, and deleting certain keys one at a time. The problem I have is if there are no more keys then, an error is thrown that says: “No action to delete keyframes from…”

So I added a check to see if there is animation data with the following:

if bpy.data.objects[ob.name].animation_data.action != None:

I need to call it at every frame to check for keys before I try to delete something.

That works. No more errors, but the problem is, it slows down the code enormously!
What use to take less than a second can take 5 seconds with a lot of objects and a lot of frames.

Is there a better way to delete specific keys, for frames in a specific range, without having to check for animation data?

Thanks

They claim:

if bpy.data.objects[ob.name].animation_data.action is not None:

is faster when checking for None since it’s a singleton.

Other than that, no clue – would have to see what you’re doing in the actual loop.

–edit–

Or you could use a try/except block…

I tried “is not”, but that didn’t make any noticeable difference in execution time.

Here is what I’m doing:

for ob in bpy.context.selected_objects:       
              
        for i in range(keyframe_start, keyframe_end + 1, step):
                            
            if check_location: 
                if bpy.data.objects[ob.name].animation_data.action != None:
                    #Action data exists.
                     ob.keyframe_delete ('location', frame = i)    
                else:
                    #No data.
                    break    

It is not very complicated, but checking every frame for every object bogs things down.

I considered the “Try/Except” method to catch the error, but that seems like a hack to me. I’ll do it, if it’s the only way. I usually try not to intentionally write code that creates errors. But if it works, it works, I guess.

Thanks

Well I put it in a Try/Except block, and that solved the problem. The exception is raised on the first frame after the frame where the last keyframe is deleted. Now the loop executes very fast.

Looks like this:

for ob in bpy.context.selected_objects:       
        #Test to see if animation data exists to avoid an error on delete with no data.
        if bpy.data.objects[ob.name].animation_data.action != None:
            #Data exists, but a further test (too slow) below is necessary,
            #so use a "try, except" block to catch it instead.            
            
            for i in range(keyframe_start, keyframe_end + 1, step):
              
                if check_location: 
                    try:
                        ob.keyframe_delete ('location', frame = i)    
                    
                    except RuntimeError:
                        #No Data.  This is triggered on the frame, after the frame,
                        # where the last keyframe was found and deleted.
                        break

the check (is not None) could be taken out of the inner loop