absolute path to a file
Paul, I can see we must train you in the interleaved response style :-)
On 18Aug2019 17:29, Paul St George <email at paulstgeorge.com> wrote:
>On 18/08/2019 02:03, Cameron Simpson wrote:
>1: Is image01.tif a real existing file when you ran this code?
>Yes. image01.tif is real, existing and apparent.
But in what directory? What is its _actual_ full path as you expect it
>>>> print(obj.name,'uses',n.image.name,'saved at',n.image.filepath,
>'which is at', realpath(n.image.filepath))
>Plane uses image01.tif saved at //image01.tif which is at /image01.tif
>(Chris and Peter lead me to believe that Blender has a special kind of
>relative path. The double slashes replace the path to the blend file?s
>directory.) realpath has done something but I know not what.
I expect that realpath has normalised the string '//image01.tif' into
the normal UNIX path '/image01.tif'. Because realpath works with UNIX
paths, '//image01.tif' is not the path to an existing file from its
point of view, because that would be in / ('//' is equivalent to '/' in
UNIX, because multiple slashes coalesce).
>What is your current working directory when you run this code?
>Well, there at least two answers to that question. Within Blender's
Did you run the other code in Blender's Console?
The thing to bear in mind is that on many GUI desktops a GUI
application's working directory may be '/'. Specificly, _not_ your home
directory. This is because they're invoked (usually) by the desktop
manager programme. And also because it sidesteps awkward situations like
having the working directory in some removable medium such as a thumb
drive, which might get removed.
So the Blender CWD is _not_ your home directory or whatever directory
your terminal prompt may be in.
And therefore things that depend on the current directory will behave
counterintuitively. In your case, by getting '/' from os.getcwd().
So: if the image01.tif file is _not_ in '/' (which I expect to be the
case) then Python's realpath will be doing a lexical operation because
as far as it is concerned the pathname ('//image01.tif') is not the path
of an existing file. And its getcwd() isn't what you expect, thus the
result not being what you want.
>But I am *guessing* the real location of the CWD is
This isn't a meaningful statement to me. The CWD is the working
directory of the python interpreter running your code. If that is the
Blender Console and the consale says the cwd is '/', then that's what it
In particular, if you invoke some Python script as /path/to/script.py,
your cwd does not magicly become '/path/to'.
The cwd is a per process ephemeral thing, which is why the shell "cd"
command works: it switches the working directory for the shell, and that
context is inherited by child processes (your commands).
>I tried using realpath, bpy.path.abspath, and os.path.abspath on this
>forward slash but nothing changed.
Because the leading slash makes it an absolute path by UNIX rules. The
cwd never gets a look in; it is irrelevant.
>For amusement, I also tried print(os.path.join(os.getcwd(), os.getcwd()))
os.path.join is pretty lexical; it largely exists to avoid wiring in an
OS-dependent path separator into your code (eg Windows' '\\' versus UNIX
'/' or OS9 ':'). But it notices an absolute path in the sequence and
discards earlier values, so the second getcwd is kept; not sure why this
is useful behaviour. But putting an absolute path on the right hand end
of a join isn't meaningful either, so the result is at best amusing
>If the underlying OS realpath fails, the Python library function might
>fall back on os.path.join(os.getcwd(), filename).
>It should, shouldn?t it. But it doesn?t.
Well, I over simplified. If your path doesn't stat() (== "resolve
directly to a filesystem object", on which the OS realpath relies),
Python's realpath seems to be doing a _purely lexical_ path
normalisation, like os.path.normpath.
So, what have you passed in? '//image01.tif'. That is an absolute path.
The cwd is not relevant, realpath runs with it as is. 'image01.tif' is
not in '/', so it doesn't stat(), so we just normalise the path to
'image01.tif' (your n.image.filepath[2:], to skip the Blender specific
'//' relative pathname notation). That is a relative path. Can we stat
it? That will happen in the Python interpreter's cwd, which apparently
is Blender's cwd, which is '/'. And there's no '/image01.tif', so it
doesn't stat. Back to lexcial work:
which becomes '/image01.tif'.
>Anyway, wouldn?t this be an absolute path via the location of the CWD?
That's not a meaningful term to me.
An absolute path begins with a slash and doesn't depend on the cwd to
locate the filesystem object.
A relative path does not begin with a slash, and uses the cwd as the
starting point to locate the filesystem object.
I suspect that you need to resolve two issues:
1: What is the working directory in which image01.tif actually resides?
It looks like that is _not_ the getcwd() which Blender gets, because it
is a GUI app whose cwd is not your work area. That will cause _all_
relative paths to resolve incorrectly from your pointof view.
2: Are you getting a path for image01.tif from Blender using its special
relative path notation, the leading '//'?
Which is alluded to here:
If you're working with such a path, you want to transform this into a
path to the directory from this the "Blender relative" path was
obtained, such as the directory used in some file chooser dialogue box.
So you might want to write an unBlenderiser (untested example):
from os.path import isabs, join as joinpath
def unblenderise(filename, context_dir=None):
# transmute Blender "relative" path
filename = filename[2:]
if not isabs(filename) and context_dir is not None:
# attach the filename to `context_dir` if supplied
filename = joinpath(context_dir, filename)
The idea here is to get back a meaningful UNIX path from a Blender path.
It first strips a leading '//'. Next, _if_ the filename is relative
_and_ you supplied the optional context_dir (eg the directory used for a
file brwoser dialogue box), then it prepends that context directory.
This _does not_ call abspath or realpath or anything, it just returns a
filename which can be used with them.
The idea is that if you know where image01.tif lives, you could supply
that as the context directory.
3: We could grip it by the husk.
Cameron Simpson <cs at cskk.id.au>