I am developing some custom nodes and have a question about the development lifecycle. Can I reload AN classes without restarting Blender? Or, do I need to reload blender after each change to the class’s source file? I have tried a few things using importLib and nothing works. Thanks!
If you can reload your changes without closing Blender depends on what you changed. First of all: you don't have to write any reloading code yourself, everything is handled automatically in the developer_utils.py file.
The problem with reloading when you have so many modules is that you can't reload the whole addon at once (please correct me if I'm wrong). Instead each module is reloaded individually.
Here is an example that shows the problem that can happen:
# file_a.py def my_func(): return 0 # file_b.py from file_a import my_func print(my_func())
file_b is executed everything looks normal and the console output will be 0. Now imagine you change
my_func so that it returns 1. After this change the reloading order is important.
There are two different scenarios:
file_b.py: In this case everything works as expected,
my_funcwill be updated at first, then the updated function is imported into
file_band the output will be 1.
file_bimports the old function again (the one that returns 0) because
file_ahas not been reloaded yet. Then output will still be 0.
In general you can simply try to reload all addons by hitting F8. Sometimes it helps to reload twice to make sure that all modules use the updated functions. There is still a good chance that two modules which depend on the same module will have different versions of the same function but in most cases you don't need to care about that.
Currently there is only one module in AN that needs to be reloaded before all the others: https://github.com/JacquesLucke/animation_nodes/blob/master/utils/handlers.py#L6
Reloading should definitly work when you only changed a single file. Maybe you have to reload twice (I hit F8 twice all the time..).
Reloading does not work (only if you are lucky) when you added/removed a function from a module that is imported into other modules.
Most of the time I just try it and when it doesn't work I restart Blender. Take a look into the console if any exception is raised (also note that not all exceptions have to come from AN; other actived addons might not support reloading)
The best way to apply changes made to an addon is to disable then re-enable the addon. If the addon has been made right this will un-register any classes, properties and other changes that have been made by the addon, allowing the new adjusted code to be used without conflicts.
When you create an addon, or add to another addon, any classes need to be registered in the addons
register() function with a matching unregister added to the
unregister() function. Other steps can be added to these functions, as in the following example an item is added and removed from the import menu. Custom properties may also be added in register and then deleted in unregister. There is also a
register_module() available that can make things easy for some addons.
When you disable the addon, the code that was read when you enabled the addon is used (which is the old
unregister()), then when you re-enable it, the modifications are noticed and the file is re-read so that the new version is in use. If you look in the console when you re-enable the addon after you make changes you will see something like -
module changed on disk: /path/to/scripts/addons_contrib/test1.py reloading...
Here is a trimmed down copy of the import template included with blender showing the use of register and unregister.
import bpy class ImportSomeData(Operator, ImportHelper): """This appears in the tooltip of the operator and in the generated docs""" bl_idname = "import_test.some_data" bl_label = "Import Some Data" #class methods here def menu_func_import(self, context): self.layout.operator(ImportSomeData.bl_idname, text="Text Import Operator") def register(): bpy.utils.register_class(ImportSomeData) bpy.types.INFO_MT_file_import.append(menu_func_import) def unregister(): bpy.utils.unregister_class(ImportSomeData) bpy.types.INFO_MT_file_import.remove(menu_func_import) if __name__ == "__main__": register()