In some cases when Blender starts it is necessary to make the add-on to be registered in last, after all other add-ons have been registered. This may be needed if the add-on conflicts with other add-ons or uses functionality from other add-ons, which should be available already during its registration.
When Blender starts, add-ons are loaded in order, according to the “bpy.context.preferences.addons” list, the order of add-ons in which is determined by they were activated by the user.
We can write the required order of activation of the add-on in its installation instructions or, using the fact that the list of add-ons is already available to us when the add-on is registering, add the functionality we need in the “register” function of the add-on.
Let’s write classes for two simple add-ons: The “First” and the “Second”.
The “First” add-on class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import bpy bl_info = { 'name': 'FIRST', 'category': 'All', 'version': (0, 0, 1), 'blender': (3, 4, 0), } class FIRST_OT_main(bpy.types.Operator): bl_idname = 'first.main' bl_label = 'First main OP' bl_options = {"REGISTER"} def execute(self, context): print('FIRST ADD-ON OPERATOR EXECUTE') return {"FINISHED"} def register(): print('FIRST add-on loaded') bpy.utils.register_class(FIRST_OT_main) def unregister(): bpy.utils.unregister_class(FIRST_OT_main) if __name__ == '__main__': register() |
The “Second” add-on class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import bpy bl_info = { 'name': 'SECOND', 'category': 'All', 'version': (0, 0, 1), 'blender': (3, 4, 0), } class SECOND_OT_main(bpy.types.Operator): bl_idname = 'second.main' bl_label = 'Second main OP' bl_options = {"REGISTER"} def execute(self, context): print('SECOND ADD-ON OPERATOR EXECUTE') return {"FINISHED"} def register(): print('SECOND add-on loaded') bpy.utils.register_class(SECOND_OT_main) def unregister(): bpy.utils.unregister_class(SECOND_OT_main) if __name__ == '__main__': register() |
Pay attention to the call of the “print” command in the “register” function of add-ons. With its help, we will track the actual loading order of our add-ons.
Save the classes in separate .py files and install add-ons from these files to Blender. First, install the “Second” add-on and after it – the “First” add-on. Don’t forget to save the user settings.
Walking through the “bpy.context.preferences.addons” list:
1 2 3 4 5 6 |
for addon in bpy.context.preferences.addons: print(addon) # ... # <bpy_struct, Addon("second_addon") at 0x0000014EEE7283A8> # <bpy_struct, Addon("first_addon") at 0x0000014EEE729128> |
We can see that our add-ons will be loaded in order: the “Second” – the “First”.
We can verify this by running Blender from the system console to see the output from the “register” add-on functions.
Let’s make some changes to the “Second” add-on so that it will always be loaded last.
We can perform manipulations with loading the add-on inside its “register” function.
Let’s add a check to the “register” function code of the “Second” add-on to see if the add-on is in the last place in the “bpy.context.preferences.addons list”.
1 2 3 4 |
def register(): if bpy.context.preferences.addons[-1].module == __name__: print('SECOND add-on loaded after all other add-ons') bpy.utils.register_class(SECOND_OT_main) |
If success – everything works as we need, the add-on is loaded in last, and we can register its classes as usual.
And we will get into the “else” condition if Blender is already loading the add-on, but there are more add-ons in the “bpy.context.preferences.addons list” after it.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def register(): if bpy.context.preferences.addons[-1].module == __name__: print('SECOND add-on loaded after all other add-ons ->> OK') bpy.utils.register_class(SECOND_OT_main) else: print('SECOND add-on loaded from the exist place in the bpy.context.preferences.addons list ->> SKIPPING') # remove from existed place addon_prefs_ptp = bpy.context.preferences.addons.get(__name__) addon_prefs_ptp_module = addon_prefs_ptp.module bpy.context.preferences.addons.remove(addon_prefs_ptp) # and add to the last place addon_prefs_new_ptp = bpy.context.preferences.addons.new() addon_prefs_new_ptp.module = addon_prefs_ptp_module |
In this case, we get a pointer to the add-on in the “bpy.context.preferences.addons” list and use it to remove the add-on from its current position in the list.
Then we create a pointer to the new add-on in the list, it will be added to the end, and we assign it the name of our add-on.
When Blender reaches the end of the list, and the last element of the list is again the pointer to our “Second” add-on, it will try to register our add-on again, and since this time the add-on is registered from the last place in the list, its registration will succeed.
In order for the add-on not to throw an error when calling the “unregister” function, we add the additional “second_registered” variable, in which we will mark whether the add-on is really registered or not.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
second_registered = False def register(): if bpy.context.preferences.addons[-1].module == __name__: print('SECOND add-on loaded after all other add-ons ->> OK') bpy.utils.register_class(SECOND_OT_main) # mark as registered global second_registered second_registered = True else: print('SECOND add-on loaded from the exist place in the bpy.context.preferences.addons list ->> SKIPPING') # remove from existed place addon_prefs_ptp = bpy.context.preferences.addons.get(__name__) addon_prefs_ptp_module = addon_prefs_ptp.module bpy.context.preferences.addons.remove(addon_prefs_ptp) # and add to the last place addon_prefs_new_ptp = bpy.context.preferences.addons.new() addon_prefs_new_ptp.module = addon_prefs_ptp_module def unregister(): global second_registered if second_registered: bpy.utils.unregister_class(SECOND_OT_main) second_registered = False |
Let’s reinstall our add-ons, again in order, first “Second”, then – “First”.
Now if we launch Blender from the console, we will see the following output:
Blender will first try to register the “Second” add-on from its current location, registration is skipped, and the add-on is moved to the last place in the list. Then the “First” add-on is registered. After that, the “Second” add-on is really registered, the last one in the order.