Avoiding Blender's Relative paths
Blender uses a special kind of relative paths. These paths start with ”//” and are relative to the blend file they are set in. The double dashes replace the path to the blend file’s directory, or in the case of library objects they replace the full path to the file.
The problem with using these paths when scripting is that the rest of Python doesn’t understand them. If you pass them to something like Popen you would get permission or file not found errors.
This is a special pain when using String Properties in addon preferences. You can set the subtype in them to FILE_PATH
to get a nice file browser button, but there’s no way to avoid getting relative paths. Worse yet, they are relative to the current blend file. Since it’s impossible to figure out from which file they were set originally, you would be unable to resolve that path in the future.
The user can make the file browser return absolute paths by ticking the “relative” checkbox in the left panel. But why not just enforce them and save us some time and trouble?
Let’s make a callback
We can use the update
callback to force absolute paths. First we want to write a generic function to do the conversion so we can plug our properties into it.
Unfortunately Blender doesn’t make this easy. You don’t get a reference to the property that’s triggering the update, so we’ll have to pass it manually.
This function exploits a small implementation detail in the api. If you set a property’s value using array notation (square brackets) you won’t re-trigger any callbacks. On the other hand dot notation (prefs.key) triggers callbacks and causes infinite recursion.
The sane_path
lambda is just there to make things more readable (it’s a matter of taste 🙂 ). The bpy.path.abspath function from will take care of the ’//’ replacing it with the full path to the blend directory, while os.path.abspath will take care of any other relative ’../’ that might still be there.
As I mentioned earlier, we can’t use that function directly since it needs to receive a reference to the property being updated. Our actual update callback will be an anonymous function which calls make_path_sane
with the property’s name.
Notice that the update callback takes two parameters, self
(s) and context
©. I don’t use them, but you could pass them too if you wanted.
Here’s the code at work in Render+’s addon preferences:
If you want to know more the Blender manual has a section about relative paths