2
$\begingroup$

Please read before marking as duplicate!

[STORY]

In short: I have a script that needs to run on Blender startup with AddonPreferences. I'm using app handlers to "tell" it to do stuff on saving a file. I put the script in the startup folder but it doesn't load correctly. The problem is that it uses a CustomProp inside the AddonPreferences class that doesn't get installed with scripts in the startup folder and so, the script is unusable.

I need to use the script with the startup folder since it's shared across many PCs and so when I put it there it'll run on all of them. I also need to use the AddonPreferences class and have these preferences because Blender "remembers" them even after restarting. At the moment, I made the script work using a simple PropertyGroup but when the script is set to "OFF" and after that Blender is restarted, the script automatically switches back to its default value (which is normal).

So, how would I need to approach this and store the script inside the startup folder and keep my preferences?

P.S: I think I can manage using the install command every time on Blender startup, so that way my script gets installed on Blender load and will keep its addon prefs unless I make changes to the script. I'm just not sure if this is the right way to go about this and maybe there's a better and easier way?

$\endgroup$
5
  • $\begingroup$ If you are installing an addon and you want something in it to run at Blender startup, see this answer for details. Be aware that Blender has an autosave feature for preferences. If it is off, then you have to manually save the preference files for a change to persist. If all you want is a preference change to persist, then setting the preference and saving the preference file is enough, provided you're using an addon preference $\endgroup$ Nov 17, 2021 at 17:19
  • $\begingroup$ I already have the persistance for my addon to execute every time a blender project is saved. If I install my addon from the add-ons menu - it works perfectly. The problem is that I don't want to install it from there, but use the startup scripts folder instead. It's just that when running a script from that folder doesn't execute the AddonPreferences class $\endgroup$
    – Aleks K.
    Nov 17, 2021 at 18:13
  • $\begingroup$ Unfortunately, you're out of luck. AddonPreferences only work with add-ons, not arbitrary scripts, no matter how the arbitrary script is executed. Are you saying that the startup directory is mapped into the filesystem of many PCs so you only want a file in one place? If so, can't you map the addons directory the same way? $\endgroup$ Nov 17, 2021 at 18:27
  • $\begingroup$ Not really.. People use different scripts, so if I make the "addons" a coomon directory, everyone will have all scripts and this might cause some issues. Besides, even if I do that, everyone will have the script but all of them will have to manually Enable it, which is something I want to avoid. Like I said, I'll try to create another script that automatically executes on Blender startup and installs and enables this one. If they have it already installed - nothing will change and everyone will keep their preferences. $\endgroup$
    – Aleks K.
    Nov 18, 2021 at 9:22
  • $\begingroup$ Maybe you could update your question to more fully describe the environment? Are you trying to maintain a single instance of Blender for multiple users on multiple PCs but allow them some customization? You might want to look into Application Templates in that case. $\endgroup$ Nov 18, 2021 at 14:46

1 Answer 1

2
$\begingroup$

OK, since nobody gave me a better solution, I did it my way and it worked, so I decided to post it back here in case anyone wants to do it too.

[My case]

We have 20+ machines working with the same version of Blender on a local server. Since I'm making changes to the original Blender add-ons (like for example added features to OBJ Importer/Exporter and so on). So, I decided that instead of having to copy the files to everyone every time I make a change, I can just make a common folder somewhere on the server and point to it from all computers using a symbolic link. That's how all machines share the same "2.93" folder which is usually located in "C:\Program files\Blender Foundation\Blender 2.93". I'm sharing this because it's important.

[Blender startup]

So, if you copy your scripts inside the scripts/startup folder located in "C:\Users<>\AppData\Roaming\Blender Foundation\Blender\2.91\scripts\startup" - they will instantly work but if you use the scripts/startup folder in the location from above, you have to have some workarounds (not sure why this is so, but some of my scripts don't work when using this one, if anyone knows why/a workaround please share). No matter where you copy the .py script though, it won't have AddonPreferences since Blender directly executes it instead of using it as an ordinary addon, which in my case is a deal braker because I'm using the AddonPreferences to turn one of my scripts On/Off and particularly using AddonPreferences because that way Blender "remembers" which was the last state even after restarting.

[Possible Solutions]

In the end I found myself writing this question and, besides that, I had 2 possible solutions in mind. The first one was, instead of using AddonPreferences, I could just write a simple .txt/.ini (it doesn't really matter) somewhere locally, which stores the last state of the Radio Button in Blender. I didn't want to create any other files and flood everyone's computers with these things, especially if sometime in the future I create more scripts that need to use AddonPreferences for other things. So, I decided to go with the second possible solution that ended up being the one I'm using.

[Solution]

Since all computers share the same scripts/startup folder (the one fakely located in C:\Program Files...), I simply created a small script that uses app handler and activates on loading a new .blend project. It installs/reinstalls and Enables my other script (the one that needs the AddonPreferences) but it's not removing it before doing so. That way it will get if there are any updates, but also will remember the state of the Radio Button. This is the code for the "script loader":

bl_info = {
    "name": "<script name>",
    "author": "<author>",
    "version": (<version>),
    "blender": (<blender version>),
    "location": "<ui location>",
    "description": "<script description>",
    "category": "<category>"
}

import bpy
from bpy.app.handlers import persistent

@persistent
def load_scripts(dummy):

    path=r"<path to file.FILE.py>"

    bpy.ops.preferences.addon_install(
                                        overwrite=True,
                                        target='DEFAULT',
                                        filepath=path,
                                        filter_folder=True,
                                        filter_python=True,
                                        filter_glob="*.py;*.zip"
                                        )

    bpy.ops.preferences.addon_enable(module="<FILE>")

def register():
    if not load_scripts in bpy.app.handlers.load_pre:
        bpy.app.handlers.load_post.append(load_scripts)

def unregister():
    if load_scripts in bpy.app.handlers.load_pre:
        bpy.app.handlers.load_post.remove(load_scripts)

if __name__ == "__main__":
    register()

A quick note is that here [path=r""] the FILE.py part is written like that to emphasize that later on when enabling the script here [bpy.ops.preferences.addon_enable(module="")], it uses the file name.

Also, in this case I only need it for this particular addon, but the path variable can also be a list of paths and later on looped to load all scripts that you need.

I hope this helps!

P.S: After some more experimentation, it turns out that the problem comes from the fact that strings in Python are IMMUTABLE and lists are MUTABLE. So, even if I use the string method ".replace" it doesn't modify the object to which the variable points. With the case of lists however, I'm just modifying a value of the same list object instead of reassigning a new object.

$\endgroup$

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.