In Python, how can I get the correctly-cased path for a file?
--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Cool Puzzler LoFi
--
Chapters
00:00 In Python, How Can I Get The Correctly-Cased Path For A File?
00:50 Answer 1 Score 7
01:08 Answer 2 Score 13
01:30 Answer 3 Score 9
01:49 Answer 4 Score 9
02:14 Thank you
--
Full question
https://stackoverflow.com/questions/3692...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #windows #filenames
#avk47
    Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Cool Puzzler LoFi
--
Chapters
00:00 In Python, How Can I Get The Correctly-Cased Path For A File?
00:50 Answer 1 Score 7
01:08 Answer 2 Score 13
01:30 Answer 3 Score 9
01:49 Answer 4 Score 9
02:14 Thank you
--
Full question
https://stackoverflow.com/questions/3692...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #windows #filenames
#avk47
ANSWER 1
Score 13
Ned's GetLongPathName answer doesn't quite work (at least not for me). You need to call GetLongPathName on the return value of GetShortPathname. Using pywin32 for brevity (a ctypes solution would look similar to Ned's):
>>> win32api.GetLongPathName(win32api.GetShortPathName('stopservices.vbs'))
'StopServices.vbs'
ANSWER 2
Score 9
Ethan answer correct only file name, not subfolders names on the path. Here is my guess:
def get_actual_filename(name):
    dirs = name.split('\\')
    # disk letter
    test_name = [dirs[0].upper()]
    for d in dirs[1:]:
        test_name += ["%s[%s]" % (d[:-1], d[-1])]
    res = glob.glob('\\'.join(test_name))
    if not res:
        #File not found
        return None
    return res[0]
ANSWER 3
Score 9
This one unifies, shortens and fixes several approaches: Standard lib only; converts all path parts (except drive letter); relative or absolute paths; drive letter'ed or not; tolarant:
def casedpath(path):
    r = glob.glob(re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', path))
    return r and r[0] or path
And this one handles UNC paths in addition:
def casedpath_unc(path):
    unc, p = os.path.splitunc(path)
    r = glob.glob(unc + re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', p))
    return r and r[0] or path
ANSWER 4
Score 7
This python-win32 thread has an answer that doesn't require third-party packages or walking the tree:
import ctypes
def getLongPathName(path):
    buf = ctypes.create_unicode_buffer(260)
    GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
    rv = GetLongPathName(path, buf, 260)
    if rv == 0 or rv > 260:
        return path
    else:
        return buf.value