In Python, how can I get the correctly-cased path for a file?

Viewed 10740

Windows uses case-insensitive file names, so I can open the same file with any of these:

r"c:\windows\system32\desktop.ini"
r"C:\WINdows\System32\DESKTOP.ini"
r"C:\WiNdOwS\SyStEm32\DeSkToP.iNi"

etc. Given any of these paths, how can I find the true case? I want them all to produce:

r"C:\Windows\System32\desktop.ini"

os.path.normcase doesn't do it, it simply lowercases everything. os.path.abspath returns an absolute path, but each of these is already absolute, and so it doesn't change any of them. os.path.realpath is only used to resolve symbolic links, which Windows doesn't have, so it's the same as abspath on Windows.

Is there a straightforward way to do this?

12 Answers

In Python 3 you can use the pathlib's resolve():

>>> from pathlib import Path

>>> str(Path(r"C:\WiNdOwS\SyStEm32\DeSkToP.iNi").resolve())
r'C:\Windows\System32\desktop.ini'

I was looking for an even simpler version that the "glob trick" so I made this, which only uses os.listdir().

def casedPath(path):
    path = os.path.normpath(path).lower()
    parts = path.split(os.sep)
    result = parts[0].upper()
    # check that root actually exists
    if not os.path.exists(result):
        return
    for part in parts[1:]:
        actual = next((item for item in os.listdir(result) if item.lower() == part), None)
        if actual is None:
            # path doesn't exist
            return
        result += os.sep + actual
    return result

edit: it works fine by the way. Not sure that returning None when path doesn't exist is expected, but I needed this behaviour. It could raise an error instead, I guess.

Related