# How to link data from a .blend relative to the current Blender version's addons

I'm trying to link certain data-blocks (node groups) from a .blend file stored in the addon folder of the current blender version. I want to be able to switch blender version and for all the links to also be using the current Blender version's addon folder.

#Directory of a .blend file stored in the same place as the script
dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "example.blend")

#Links all node groups from the blend file.
dir += "\\NodeTree\\"
for node_group in data_from.node_groups:
if node_group is not None:
filepath  = dir + node_group  ,
directory = dir         ,
filename  = node_group
)


The library they are linked from has the directory stored as such after linking with this script:

//..\..\AppData\Roaming\Blender Foundation\Blender\2.93\scripts\addons\addon\example.blend

So if you switch to another computer or Blender version it is using the old directory (and then cannot find the correct .blend file). Not having to store the linked .blend in a user defined directory would be preferable. It just needs to work for everyone with the addon installed.

I'm not sure if there's a way to do that.

One alternative is to have your addon register some code to be run when a file is loaded that fixes up the library paths to their new location.

bl_info = {
"name" : "Test",
"blender" : (2, 93, 0),
}

import bpy
from bpy.app.handlers import persistent
import os

@persistent

for lib in bpy.data.libraries:
lib_path = bpy.path.abspath(lib.filepath)

# Pretend there is actually some code to detect
if "myLib.blend" in lib_path:

if lib_path != new_lib_path:

lib.filepath = new_lib_path

def register():

def unregister():



Tested this going between 2.93 and 3.0 and it worked.

One problem is a file will only be fixed up if the addon is enabled when the file is loaded. If the addon is disabled, and you enable it, the currently open file won't be fixed. You'd have to reopen the file.

If you want this to be portable, independent of OS versions or Blender release versions, you can use code like what I have below. It's based on Python's platform data from the sys library and Blender's Directory Layout from the Blender manual. Replace your dir = ... with this code.

It will only work for standard installations. There's no way to deal with a Blender install in a non-standard location. It also relies on the manual for names. If you're not using Windows you should verify that the generated dir string is correct. I don't have access to those systems to test against.

You also need to adjust your dir += ... code to use pathlib for portability if you want this to be portable.

import bpy
import pathlib

# for an explanation of where these strings come from and how they're used
#
version = bpy.data.version
version_string = str(version[0]) + '.' + str(version[1])
# See https://docs.python.org/3.9/library/sys.html#sys.platform
# for the supported list.  In this example I only picked a
# couple to show the outline
#
LOCAL = pathlib.Path('./' + version_string)

if pathlib.sys.platform == 'win32':
WIN32_USER = pathlib.Path(pathlib.os.getenv('USERPROFILE'))
USER = WIN32_USER / 'AppData/Roaming/Blender Foundation' / version_string
SYSTEM = USER
elif pathlib.sys.platform == 'linux':
LINUX_USER = pathlib.Path(pathlib.os.getenv('HOME'))
USER = LINUX_USER / '.config/blender' / version_string
SYSTEM = pathlib.Path('/usr/share/blender/' + version_string)
elif pathlib.sys.platform == 'darwin':
MACOS_USER = pathlib.Path(pathlib.os.getenv('USER'))
USER = '/Users' / MACOS_USER / 'Library/Application Support/Blender' / version_string
SYSTEM = pathlib.Path('/Library/Application Support/Blender/' + version_string)
else:
# I only did the 3 most common platforms.  If you want others, add more elif blocks
# to set USER and SYSTEM  Most Unix systems will work the same as linux
pass


Alternatively you can use bpy.utils.resource_path
LOCAL = pathlib.Path(bpy.utils.resource_path('LOCAL'))