1
$\begingroup$

I've noticed a lot of add-on code using the load_post handler to serve as a sort of startup event. This makes a lot of sense, because many elements do not exist before that moment, and most add-ons need to associate with them.

But what about when an add-on is activated after the blend file is loaded? The normal startup sequence seems to be load_pre, addon.register, load_post, which allows us to sync with the file contents. But how do we detect when load_post happens before our add-on is registered?

I've tried accessing bpy.data.* and bpy.context.*, to try to detect any differences, but they are both restricted at normal startup. Is there a safe way to ask the environment if any scenes exist?

Edit: Just want to sum my problem up as a really simple question: How do I initialize add-on states that need to look at scene elements?

$\endgroup$
  • $\begingroup$ Hi. If you can explain the specific situation that makes you think you need to do this, it might help. $\endgroup$ – Ray Mairlot Oct 4 '19 at 15:58
  • $\begingroup$ Just any situation where you need to look at the scene at startup would encounter the issue. For example, if an add-on actively manipulates lights, I'm assuming it would need to detect the existence of lights before it starts manipulating them. I may have explained it poorly, but I'm just trying to detect weather or not a scene already exists when my add-on starts. In my specific situation, I'm wanting to build a hierarchy table. I also have certain routines that shouldn't run unless certain scene elements are present. $\endgroup$ – Robert Oct 4 '19 at 21:17
  • 1
    $\begingroup$ After reading about it, it looks like they limited access to the scene during registration to help protect developers from themselves. But any add-on that makes use of load_post is likely to break when activated after loading a file. Whatever it does in that function will fail to happen until a new file is loaded. $\endgroup$ – Robert Oct 4 '19 at 21:38
  • $\begingroup$ You're having a hard time working around the restriction, because you're not supposed to do that. See: blender.stackexchange.com/questions/24415/… $\endgroup$ – Robert Gützkow Oct 4 '19 at 22:55
  • 1
    $\begingroup$ All the use cases you've described should not be handled when loading the add-on. Either calculate the state on the fly when the operator is executed or use something like a handler for depsgraph_update_post to continuously update the state whenever something relevant in the project changes. $\endgroup$ – Robert Gützkow Oct 5 '19 at 3:25
2
$\begingroup$

Add-ons can do per-file initialisation, if the add-on has some kind of panel in the UI somewhere.

You may notice various panels in Blender's UI have checkboxes next to the panel title. This is can be because they don't want to be active unless specifically turned on, but it can also be because they want to do some setup before being used:

enter image description here

This can be achieved in your own add-on by adding a draw_header function into the class that defines your panel:

def draw_header(self, context):

    self.layout.prop(context.scene, "addon_panel_enabled", text="")

The draw_header displays a boolean which I created and registered in the register function of the add-on:

bpy.types.Scene.addon_panel_enabled = bpy.props.BoolProperty(default=False, update=initialiseAddon)

The property has an update function called initialiseAddon which runs when the boolean is changed. It is in initialiseAddon that you can run your setup code.

Be aware, however, that this will run when the header checkbox is enabled and disabled. You could of course include code to make sure it only runs once by checking if the header boolean is true (the update function seems to be run after the value has been set):

def initialiseAddon(self, context):
    if context.scene.addon_panel_enabled:
        print("Only runs when enabling the checkbox")

Or just make another property which stores whether initialisation has been done or inspect your own data.

If you don't have a panel, then you should do initialisation in your operator when it first runs and again, have a scene property that stores whether setup has been done or not.

Full code (based on the UI Panel Simple template that comes with Blender):

import bpy

class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw_header(self, context):

        self.layout.prop(context.scene, "addon_panel_enabled", text="")

    def draw(self, context):
        layout = self.layout

        obj = context.object

        row = layout.row()
        row.label(text="Hello world!", icon='WORLD_DATA')

        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")

        row = layout.row()
        row.operator("mesh.primitive_cube_add")

def initialiseAddon(self, context):
    #Per file initialisation code here
    if context.scene.addon_panel_enabled == True:
        print("Only runs when enabling the checkbox")

def register():
    bpy.types.Scene.addon_panel_enabled = bpy.props.BoolProperty(default=False, update=initialiseAddon)
    bpy.utils.register_class(HelloWorldPanel)

def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)
    del bpy.types.Scene.addon_panel_enabled

if __name__ == "__main__":
    register()
$\endgroup$
  • $\begingroup$ That is one of the right ways to accomplish the goal. $\endgroup$ – Robert Gützkow Oct 6 '19 at 17:00
  • $\begingroup$ Yeah, any type of user event that indicates the user wants to use the add-on would be a good place to initialize. The best place for a panel add-on would be when the user expands the panel itself, but there's unfortunately no event for that. $\endgroup$ – Robert Oct 6 '19 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.