I am writing an addon that requires a function (update_focal_length) to be called each time the camera is moved. As a quick and easy way to solve this, I append this function to bpy.app.handlers.depsgraph_update_post and bpy.app.handlers.frame_change_post. This works very well.

However, after closing Blender and reopening it, I find that even though my addon registers, update_focal_length is not called upon scene change anymore. The code works great when I use the checkbox to manually un-register and re-register the addon.

In an attempt to solve this problem, I also tried appending update_focal_length to bpy.app.handlers.load_post and bpy.app.handlers.load_pre, but the behavior continues to be the same. Ideally, I would like this function to be called when a file is loaded, and continue to be called each time the scene changes after that.

Here is the relevant code:

def update_focal_length(self, context):
    # for each camera with focal_lock enabled...
    for camera in bpy.data.cameras:
        if camera.focal_lock.enable_lock and camera.focal_lock.focus_object != None:
            currentDistance = distance_to_plane(camera.focal_lock.focus_object)
            camera.lens = currentDistance * (camera.focal_lock.focal_distance_ratio)


handlers = [bpy.app.handlers.depsgraph_update_post, bpy.app.handlers.frame_change_post, bpy.app.handlers.load_post, bpy.app.handlers.load_pre]
def register():
    for cls in classes:
    bpy.types.Camera.focal_lock = bpy.props.PointerProperty(type=FocalLockSettings)

    for handler in handlers:
        [handler.remove(h) for h in handler if h.__name__ == "update_focal_length"]

def unregister():
    for cls in classes:
    del bpy.types.Camera.focal_lock

    for handler in handlers:
        [handler.remove(h) for h in handler if h.__name__ == "update_focal_length"]

if __name__ == "__main__":

Any ideas on how I may achieve this effect without users having to un-register and re-register my addon each time? Thanks so much for the help!

  • 1
    $\begingroup$ The handler aside, the add-on just adds a 'track to' constraint based on the the focus object and allows to bake the focal lenght, correct? Since the code is a bit of a mess and there is no documentation, do you mind adding a bit more details about what the add-on actually should do? $\endgroup$
    – brockmann
    Commented Aug 31, 2021 at 5:42
  • $\begingroup$ @brockmann Yeah, no problem! So the main feature is to have the ability to create the vertigo effect, as shown in this video: youtube.com/watch?v=db8TEAO8qDM. It does this by setting the camera's focal length to the current distance the camera is from an object multiplied by a the ratio between the original distance and focal length. $\endgroup$ Commented Sep 1, 2021 at 16:28

1 Answer 1


The manual says

By default handlers are freed when loading new files, in some cases you may want the handler stay running across multiple files (when the handler is part of an add-on for example).

For this the bpy.app.handlers.persistent decorator needs to be used.

and includes an example of the decorator.

persistent decorator in use

I believe this is what you are looking for; rather than trying to find a hook at load time.

  • $\begingroup$ Hey, this worked! Thank you so much! $\endgroup$ Commented Sep 6, 2021 at 14:39

You must log in to answer this question.

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