Functions such as os.path.exists(image.filepath) fail when Blender uses relative paths, This seems to be because Blender uses // prefix for relative paths, unlike the more conventional ./.

How can standard Python filesystem functions be used correctly on Blender paths?


The // prefix is Blender specific to denote relative paths used within Blender,

To use Python's filesystem functions you'll have to first expand this using:


filepath_full = bpy.path.abspath(image.filepath, library=image.library)

Unlike ./, which simply expands the current-working-directory (os.getcwd()), Blender supports library-linked files. This means the directory of the current data-block could be a different path then the currently open Blend file.

If you are operating data which the script created, You can skip passing the library argument.

filepath_full = bpy.path.abspath(image.filepath)

Note that this isn't specific to images, it works for movie-clip, sounds, sequencer and text blocks too.

  • $\begingroup$ I'm dealing with a different situation, where I just used a StringProperty with the directory setting on to pick out a destination directory. I had one person insisting that there was no need to force an absolute path. Then, tonight, testing my script, it crashed because I had not changed the setting in the file requestor to Absolute Path. This was literally the last bug to stomp out at 2 AM. Thank you - you gave me the answer and it was easy to just wrap bpy.path.abspath() around my StringProperty to always get the full path. Again, thanks! $\endgroup$
    – Tango
    Apr 20 at 7:55

This may be off topic, but if you encounter the following situation, this may help you.

I was automating the creation of blender files which

  1. Took an existing file,

  2. Replaced some textures, moved stuff around, changed sizes of some objects etc.,


I couldn't figure out why in the saved file, all textures had relative paths assigned to them, even though in all possible settings in Blender I set relative paths to False, like the setting User Preferences / File / Save & Load / Relative Paths to [ ] (unchecked) and using bpy.context.user_preferences.filepaths.use_relative_paths = False.

All textures still had their paths in the form '//.../.../...' which was not what I wanted AND those paths were relative TO THE LOCATION OF THE ORIGINAL BLENDER FILE and not relative to the newly saved one.

Then it dawned to me, but this is not documented anywhere, that the problem is not where I had expected it, but rather when the new file is being saved. I used the method bpy.ops.wm.save_as_mainfile() and this method, as it turned out, was the reason. It has an optional argument relative_remap WHICH DEFAULTS TO True and means that THE MOMENT you save your new file, all paths get converted to relative (and relative to the location of the currently open file, not to the location where your new file is being saved to). Hope this saves you some time, it took me hours to figure out.

So, you need

bpy.ops.wm.save_as_mainfile(filepath = YourNewFilePath, relative_remap = False)

  • 2
    $\begingroup$ Cant upvote this enough. $\endgroup$
    – RDK
    May 9 '19 at 5:05
  • 1
    $\begingroup$ Ditto - this answer saved me. $\endgroup$ Jun 10 '20 at 4:12

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.