What is the best method for storing a variable that's callable in the register() function?

Here is the workflow for the add-on I’m designing:

  1. User download, installs, and activates add-on.
  2. User sets a path variable in the add-on preferences section, here the StringProperty is labeled Environment Path:


3. Example.zip file is installed to Environment Path when user clicks the Install dependencies button.
4. User quits Blender

My question: How do I store the Environment Path string that the user just inputted so I can call it in the register() function when the user starts Blender again?

I need to check that Example.zip is installed every time the add-on is booted up, restarted, or when Blender starts so that I can display the correct panels: One panel when Example.zip isn’t installed, instructing the user on how to install it. And another panel that has the normal add-on functionality when Example.zip is installed.

I’ve tried the following methods, yet each one has it’s gotchas:

  • Using Environment Variables with os.enviorn or os.getenv: Environment variables are temporary to the current shell Python is running, meaning that they disappear from system memory when Blender is shutdown.
  • Using StringProperty() as outlined in this post: python - How do you save a variable in blender addon? - Blender Stack Exchange Unable to reference the StringProperty with context.preferences.addons[__name__].preferences.environment_path since context is restricted until the add-on is registered.
  • Storing the path in a path_log.json file: it’s unreliable and messy, the user must start Blender with admin permissions if the log is to be saved within the add-ons directory.

Here is an example of what I’m trying to do:

def register():
    for cls in pre_dependency_classes:
        bpy.utils.register_class(cls)

    environment_path = some_method_to_get_var()  # This is what I'm looking for

    if environment_path and os.path.exists(environment_path):
        for cls in classes:
            bpy.utils.register_class(cls)

Thank you for reading, I’d appreciate any help I can get. Please let me know if I can further clarify anything!

1 Like

I had this problem recently, and my solution was a mix of yours:

  • Have a StringProperty in the addon preferences that is used to set the path
  • In the update function of that property, write the value to a file in the addon directory (I’m not sure what you mean about needing admin permissions, I never ran into a problem with that…)
  • In the register function, open the file and read the contents.

Sure it’s a bit finicky, but in the end it’s not especially hard to set up, and is pretty reliable (though potentially vulnerable to errors occurring when writing the file that could leave it blank).

And if there’s some easy method that I’m missing, I’d love to hear that as well :sweat_smile:

1 Like

Thank you so much, was beginning to lose hope. I’ll try this method out, very promising :grinning:

1 Like

Wow, ok awesome, just got it to work, thank you so much for the help!! I managed to get the file to save, I believe I was initially getting the wrong path due to Blenders weird path system.

Thank you so much @Strike_Digital, life saver!

1 Like

the defacto standard way of dealing with this limitation is to register a timer with a first_interval of something ridiculously low like .1, and then do all of the context restricted stuff in the deferred function

1 Like

Great, glad I could help out!

@testure I had wondered about that, but I always saw online that it was a pretty hacky way of doing stuff and that there was some reason you shouldn’t use it.

I wouldn’t say it’s hacky per-se, it’s just in lieu of something more official like a late_register() or something along those lines. The only reason the context restriction exists is because there’s no guarantee that certain aspects of bpy.context are even created yet, thus by waiting until the next frame everything should be ready to go.

In a perfect world we’d have an event/subscriber API and could just have a function that is automatically called as soon as context is ready, but alas.

1 Like