Filename case-insensitivity on OS X

Tom Anderson twic at urchin.earth.li
Tue Jan 3 09:29:41 EST 2006


Afternoon all,

MacOS X seems to have some heretical ideas about the value of case in 
paths - it seems to believe that it doesn't exist, more or less, so "touch 
foo FOO" touches just one file, you can't have both 'makefile' and 
'Makefile' in the same directory, 
"os.path.exists(some_valid_path.upper())" returns True even when 
"os.path.split(some_valid_path.upper())[1] in 
os.listdir(os.path.split(some_valid_path)[0])" returns False, etc 
(although, of course, "ls *.txt" doesn't mention any of those .TXT files 
lying around).

Just to prove it, here's what unix (specifically, linux) does:

twic at urchin:~$ uname
Linux
twic at urchin:~$ python
Python 2.3.5 (#2, Sep  4 2005, 22:01:42)
[GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> filenames = os.listdir(".")
>>> first = filenames[0]
>>> first in filenames
True
>>> first.upper() in filenames
False
>>> os.path.exists(os.path.join(".", first))
True
>>> os.path.exists(os.path.join(".", first.upper()))
False
>>>

And here's what OS X does:

Hooke:~ tom$ uname
Darwin
Hooke:~ tom$ python
Python 2.4.1 (#2, Mar 31 2005, 00:05:10)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1666)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> filenames = os.listdir(".")
>>> first = filenames[0]
>>> first in filenames
True
>>> first.upper() in filenames
False
>>> os.path.exists(os.path.join(".", first))
True
>>> os.path.exists(os.path.join(".", first.upper()))
True
>>>

Sigh. Anyone got any bright ideas for working around this, specifically 
for os.path.exists? I was hoping there was some os.path.actualpath, so i 
could say:

def exists_dontignorecase(path):
 	return os.path.exists(path) and (path == os.path.actualpath(path))

Java has a java.io.File.getCanonicalPath method that does this, but i 
can't find an equivalent in python - is there one?

I can emulate it like this:

def _canonicalise(s, l):
 	s = s.lower()
 	for t in l:
 		if s == t.lower():
 			return t
 	raise ValueError, ("could not canonicalise string", s)

def canonicalpath(path):
 	if (path in ("/", "")):
 		return path
 	parent, child = os.path.split(path)
 	cparent = canonicalpath(parent)
 	cchild = _canonicalise(child, os.listdir(cparent))
 	return os.path.join(cparent, cchild)

Or, more crudely, do something like this:

def exists_dontignorecase(path):
 	dir, f = os.path.split(path)
 	return f in os.listdir(dir)

But better solutions are welcome.

Thanks,
tom

-- 
Infantry err, infantry die. Artillery err, infantry die. -- IDF proverb



More information about the Python-list mailing list