8
$\begingroup$

I'm doing simple handler script that gets appended to bpy.app.handlers.frame_change_post.

Every time I do a changes to it and hit Alt+P it registers itself again with a new version. after a bit I have 10 of the scripts running happily on every frame change.

How can I get rid of the old running versions without closing and reopening Blender, which seems to be the only option now?

I tried adding unregistering with bpy.app.handlers.frame_change_post.remove() but that is just throwing an error as if my script wasn't on the list. while at the same time print(bpy.app.handlers.frame_change_post) is showing my function name there in growing numbers :)

so, what's the best practice developing and running these?

thanks.

.b

$\endgroup$

3 Answers 3

12
$\begingroup$

In simple cases when you're not having to deal with other handlers, you can clear all handlers before adding new ones:

bpy.app.handlers.frame_change_post.clear()

However for projects which are already using handlers, you may not want to remove everyone elses handlers, and instead replace only a handlers the script added.

Currently we don't have a convenient way to handle this, or at least Python doesn't make it so easy to reference a function defined in a previous execution.

This example script shows how the functions name and module can be used, append_function_unique is a function to append and remove previous instances.

import bpy

def append_function_unique(fn_list, fn):
    """ Appending 'fn' to 'fn_list',
        Remove any functions from with a matching name & module.
    """
    fn_name = fn.__name__
    fn_module = fn.__module__
    for i in range(len(fn_list) - 1, -1, -1):
        if fn_list[i].__name__ == fn_name and fn_list[i].__module__ == fn_module:
            del fn_list[i]
    fn_list.append(fn)


def my_function(scene):
    print(scene)

def register():
    append_function_unique(bpy.app.handlers.frame_change_post, my_function)

if __name__ == "__main__":
    register()

Note: This is isn't such a problem for modules (add-ons or scripts you import). However scripts you run directly will use a module name of __main__. This means if you run multiple scripts directly, there may be function naming collisions - which is why this solution isn't ideal.

$\endgroup$
1
1
$\begingroup$

While developing in the text editor I tend to use bpy.app.handlers.frame_change_post.clear() to remove all handlers, but this may conflict with other scripts as it won't just remove the functions you appended.

If you want to use .remove() then you need to specify the function that you originally appended to the handler. E.g. if you originally did: bpy.app.handlers.frame_change_post.append(my_function_name) you would do bpy.app.handlers.frame_change_post.remove(my_function_name) to remove it.

$\endgroup$
3
  • $\begingroup$ thanks, the bpy.app.handlers.frame_change_post.remove(my_function_name) I tried to use, but all I got was error: ValueError: list.remove(x): x not in list $\endgroup$
    – basse
    Commented Jun 1, 2016 at 14:07
  • $\begingroup$ @basse I think maybe if you use clear() to clear everything out then you will be able to use remove() after that. $\endgroup$ Commented Jun 1, 2016 at 14:11
  • $\begingroup$ An important node, my_function_name must be a string literal like "my_function", or a name of a variable holding the string of a function. It can't be the name of a function, meaning a 'pointer' to the function, because when you run a new script, this will be a new function, with a different identity, therefore it will not be found in the list of handlers. $\endgroup$ Commented Apr 26, 2023 at 10:52
0
$\begingroup$

I want to provide a simple way to remove an item from handlers list using shallow copy of list of handlers:

for func in bpy.app.handlers.frame_change_post[:]:
    if func.__name__ == 'your_funciton_name':
        bpy.app.handlers.frame_change_post.remove(func)
$\endgroup$

You must log in to answer this question.

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