posixpath.py revision edbb763a2b63074cd468a5d33a17908b2cc0654
1edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""Common operations on Posix pathnames. 2edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 3edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepInstead of importing this module directly, import os and refer to 4edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepthis module as os.path. The "os.path" name is an alias for this 5edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmodule on Posix systems; on other systems (e.g. Mac, Windows), 6edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepos.path provides the same operations in a manner specific to that 7edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepplatform, and is an alias to another module (e.g. macpath, ntpath). 8edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 9edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSome of this can actually be useful on non-Posix systems too, e.g. 10edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfor manipulation of the pathname component of URLs. 11edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""" 12edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 13edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport os 14edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport sys 15edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport stat 16edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport genericpath 17edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport warnings 18edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom genericpath import * 19edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 20edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptry: 21edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep _unicode = unicode 22edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepexcept NameError: 23edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # If Python is built without Unicode support, the unicode type 24edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # will not exist. Fake one. 25edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep class _unicode(object): 26edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 27edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 28edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep__all__ = ["normcase","isabs","join","splitdrive","split","splitext", 29edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "basename","dirname","commonprefix","getsize","getmtime", 30edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "getatime","getctime","islink","exists","lexists","isdir","isfile", 31edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "ismount","walk","expanduser","expandvars","normpath","abspath", 32edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "samefile","sameopenfile","samestat", 33edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "curdir","pardir","sep","pathsep","defpath","altsep","extsep", 34edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "devnull","realpath","supports_unicode_filenames","relpath"] 35edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 36edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# strings representing various path-related bits and pieces 37edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepcurdir = '.' 38edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeppardir = '..' 39edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepextsep = '.' 40edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsep = '/' 41edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeppathsep = ':' 42edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdefpath = ':/bin:/usr/bin' 43edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepaltsep = None 44edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdevnull = '/dev/null' 45edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 46edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac. 47edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# On MS-DOS this may also turn slashes into backslashes; however, other 48edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# normalizations (such as optimizing '../' away) are not allowed 49edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# (another function should be defined to do that). 50edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 51edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef normcase(s): 52edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Normalize case of pathname. Has no effect under Posix""" 53edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return s 54edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 55edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 56edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Return whether a path is absolute. 57edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Trivial in Posix, harder on the Mac or MS-DOS. 58edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 59edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef isabs(s): 60edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Test whether a path is absolute""" 61edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return s.startswith('/') 62edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 63edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 64edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Join pathnames. 65edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Ignore the previous parts if a part is absolute. 66edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Insert a '/' unless the first part is empty or already ends in '/'. 67edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 68edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef join(a, *p): 69edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Join two or more pathname components, inserting '/' as needed. 70edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep If any component is an absolute path, all previous path components 71edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep will be discarded. An empty last part will result in a path that 72edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep ends with a separator.""" 73edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = a 74edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep for b in p: 75edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if b.startswith('/'): 76edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = b 77edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep elif path == '' or path.endswith('/'): 78edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path += b 79edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep else: 80edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path += '/' + b 81edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return path 82edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 83edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 84edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Split a path in head (everything up to the last '/') and tail (the 85edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# rest). If the path ends in '/', tail will be empty. If there is no 86edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# '/' in the path, head will be empty. 87edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Trailing '/'es are stripped from head unless it is the root. 88edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 89edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef split(p): 90edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Split a pathname. Returns tuple "(head, tail)" where "tail" is 91edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep everything after the final slash. Either part may be empty.""" 92edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = p.rfind('/') + 1 93edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep head, tail = p[:i], p[i:] 94edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if head and head != '/'*len(head): 95edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep head = head.rstrip('/') 96edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return head, tail 97edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 98edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 99edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Split a path in root and extension. 100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# The extension is everything starting at the last dot in the last 101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# pathname component; the root is everything before that. 102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# It is always true that root + ext == p. 103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef splitext(p): 105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return genericpath._splitext(p, sep, altsep, extsep) 106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsplitext.__doc__ = genericpath._splitext.__doc__ 107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Split a pathname into a drive specification and the rest of the 109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. 110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef splitdrive(p): 112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Split a pathname into drive and path. On Posix, drive is always 113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep empty.""" 114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return '', p 115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Return the tail (basename) part of a path, same as split(path)[1]. 118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef basename(p): 120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Returns the final component of a pathname""" 121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = p.rfind('/') + 1 122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return p[i:] 123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Return the head (dirname) part of a path, same as split(path)[0]. 126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef dirname(p): 128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Returns the directory component of a pathname""" 129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = p.rfind('/') + 1 130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep head = p[:i] 131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if head and head != '/'*len(head): 132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep head = head.rstrip('/') 133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return head 134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Is a path a symbolic link? 137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# This will always return false on systems where os.lstat doesn't exist. 138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef islink(path): 140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Test whether a path is a symbolic link""" 141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep st = os.lstat(path) 143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except (os.error, AttributeError): 144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return False 145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return stat.S_ISLNK(st.st_mode) 146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Being true for dangling symbolic links is also useful. 148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef lexists(path): 150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Test whether a path exists. Returns True for broken symbolic links""" 151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep os.lstat(path) 153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except os.error: 154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return False 155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return True 156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Are two filenames really pointing to the same file? 159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef samefile(f1, f2): 161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Test whether two pathnames reference the same actual file""" 162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep s1 = os.stat(f1) 163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep s2 = os.stat(f2) 164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return samestat(s1, s2) 165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Are two open files really referencing the same file? 168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# (Not necessarily the same file descriptor!) 169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef sameopenfile(fp1, fp2): 171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Test whether two open file objects reference the same file""" 172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep s1 = os.fstat(fp1) 173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep s2 = os.fstat(fp2) 174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return samestat(s1, s2) 175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Are two stat buffers (obtained from stat, fstat or lstat) 178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# describing the same file? 179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef samestat(s1, s2): 181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Test whether two stat buffers reference the same file""" 182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return s1.st_ino == s2.st_ino and \ 183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep s1.st_dev == s2.st_dev 184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Is a path a mount point? 187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) 188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef ismount(path): 190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Test whether a path is a mount point""" 191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if islink(path): 192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # A symlink can never be a mount point 193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return False 194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep s1 = os.lstat(path) 196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep s2 = os.lstat(join(path, '..')) 197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except os.error: 198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return False # It doesn't exist -- so not a mount point :-) 199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep dev1 = s1.st_dev 200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep dev2 = s2.st_dev 201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if dev1 != dev2: 202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return True # path/.. on a different device as path 203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep ino1 = s1.st_ino 204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep ino2 = s2.st_ino 205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if ino1 == ino2: 206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return True # path/.. is the same i-node as path 207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return False 208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Directory tree walk. 211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# For each directory under top (including top itself, but excluding 212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# '.' and '..'), func(arg, dirname, filenames) is called, where 213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# dirname is the name of the directory and filenames is the list 214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# of files (and subdirectories etc.) in the directory. 215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# The func may modify the filenames list, to implement a filter, 216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# or to impose a different order of visiting. 217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef walk(top, func, arg): 219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Directory tree walk with callback function. 220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep For each directory in the directory tree rooted at top (including top 222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep itself, but excluding '.' and '..'), call func(arg, dirname, fnames). 223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep dirname is the name of the directory, and fnames a list of the names of 224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep the files and subdirectories in dirname (excluding '.' and '..'). func 225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep may modify the fnames list in-place (e.g. via del or slice assignment), 226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep and walk will only recurse into the subdirectories whose names remain in 227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep fnames; this can be used to implement a filter, or to impose a specific 228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep order of visiting. No semantics are defined for, or required of, arg, 229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep beyond that arg is always passed to func. It can be used, e.g., to pass 230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep a filename pattern, or a mutable object designed to accumulate 231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep statistics. Passing None for arg is common.""" 232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.", 233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep stacklevel=2) 234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep names = os.listdir(top) 236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except os.error: 237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return 238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep func(arg, top, names) 239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep for name in names: 240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep name = join(top, name) 241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep st = os.lstat(name) 243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except os.error: 244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep continue 245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if stat.S_ISDIR(st.st_mode): 246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep walk(name, func, arg) 247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Expand paths beginning with '~' or '~user'. 250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# '~' means $HOME; '~user' means that user's home directory. 251edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# If the path doesn't begin with '~', or if the user or $HOME is unknown, 252edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# the path is returned unchanged (leaving error reporting to whatever 253edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# function is called with the expanded path as argument). 254edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# See also module 'glob' for expansion of *, ? and [...] in pathnames. 255edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# (A function should also be defined to do full *sh-style environment 256edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# variable expansion.) 257edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 258edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef expanduser(path): 259edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Expand ~ and ~user constructions. If user or $HOME is unknown, 260edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep do nothing.""" 261edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not path.startswith('~'): 262edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return path 263edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = path.find('/', 1) 264edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if i < 0: 265edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = len(path) 266edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if i == 1: 267edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if 'HOME' not in os.environ: 268edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep import pwd 269edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep userhome = pwd.getpwuid(os.getuid()).pw_dir 270edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep else: 271edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep userhome = os.environ['HOME'] 272edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep else: 273edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep import pwd 274edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 275edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pwent = pwd.getpwnam(path[1:i]) 276edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except KeyError: 277edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return path 278edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep userhome = pwent.pw_dir 279edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep userhome = userhome.rstrip('/') 280edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return (userhome + path[i:]) or '/' 281edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 282edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 283edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Expand paths containing shell variable substitutions. 284edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# This expands the forms $variable and ${variable} only. 285edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Non-existent variables are left unchanged. 286edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 287edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_varprog = None 288edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 289edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef expandvars(path): 290edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Expand shell variables of form $var and ${var}. Unknown variables 291edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep are left unchanged.""" 292edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep global _varprog 293edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if '$' not in path: 294edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return path 295edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not _varprog: 296edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep import re 297edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep _varprog = re.compile(r'\$(\w+|\{[^}]*\})') 298edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = 0 299edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep while True: 300edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep m = _varprog.search(path, i) 301edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not m: 302edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep break 303edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i, j = m.span(0) 304edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep name = m.group(1) 305edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if name.startswith('{') and name.endswith('}'): 306edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep name = name[1:-1] 307edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if name in os.environ: 308edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep tail = path[j:] 309edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = path[:i] + os.environ[name] 310edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = len(path) 311edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path += tail 312edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep else: 313edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = j 314edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return path 315edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 316edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 317edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. 318edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# It should be understood that this may change the meaning of the path 319edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# if it contains symbolic links! 320edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 321edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef normpath(path): 322edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Normalize path, eliminating double slashes, etc.""" 323edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Preserve unicode (if path is unicode) 324edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep slash, dot = (u'/', u'.') if isinstance(path, _unicode) else ('/', '.') 325edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if path == '': 326edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return dot 327edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep initial_slashes = path.startswith('/') 328edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # POSIX allows one or two initial slashes, but treats three or more 329edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # as single slash. 330edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if (initial_slashes and 331edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path.startswith('//') and not path.startswith('///')): 332edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep initial_slashes = 2 333edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep comps = path.split('/') 334edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep new_comps = [] 335edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep for comp in comps: 336edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if comp in ('', '.'): 337edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep continue 338edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if (comp != '..' or (not initial_slashes and not new_comps) or 339edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep (new_comps and new_comps[-1] == '..')): 340edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep new_comps.append(comp) 341edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep elif new_comps: 342edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep new_comps.pop() 343edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep comps = new_comps 344edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = slash.join(comps) 345edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if initial_slashes: 346edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = slash*initial_slashes + path 347edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return path or dot 348edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 349edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 350edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef abspath(path): 351edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Return an absolute path.""" 352edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not isabs(path): 353edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if isinstance(path, _unicode): 354edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep cwd = os.getcwdu() 355edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep else: 356edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep cwd = os.getcwd() 357edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = join(cwd, path) 358edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return normpath(path) 359edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 360edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 361edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Return a canonical path (i.e. the absolute location of a file on the 362edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# filesystem). 363edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 364edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef realpath(filename): 365edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Return the canonical path of the specified filename, eliminating any 366edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsymbolic links encountered in the path.""" 367edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path, ok = _joinrealpath('', filename, {}) 368edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return abspath(path) 369edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 370edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Join two paths, normalizing ang eliminating any symbolic links 371edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# encountered in the second path. 372edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef _joinrealpath(path, rest, seen): 373edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if isabs(rest): 374edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep rest = rest[1:] 375edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = sep 376edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 377edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep while rest: 378edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep name, _, rest = rest.partition(sep) 379edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not name or name == curdir: 380edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # current dir 381edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep continue 382edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if name == pardir: 383edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # parent dir 384edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if path: 385edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path, name = split(path) 386edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if name == pardir: 387edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = join(path, pardir, pardir) 388edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep else: 389edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = pardir 390edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep continue 391edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep newpath = join(path, name) 392edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not islink(newpath): 393edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = newpath 394edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep continue 395edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Resolve the symbolic link 396edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if newpath in seen: 397edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Already seen this path 398edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path = seen[newpath] 399edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if path is not None: 400edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # use cached value 401edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep continue 402edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # The symlink is not resolved, so we must have a symlink loop. 403edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Return already resolved part + rest of the path unchanged. 404edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return join(newpath, rest), False 405edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep seen[newpath] = None # not resolved symlink 406edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path, ok = _joinrealpath(path, os.readlink(newpath), seen) 407edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not ok: 408edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return join(path, rest), False 409edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep seen[newpath] = path # resolved symlink 410edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 411edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return path, True 412edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 413edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 414edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsupports_unicode_filenames = (sys.platform == 'darwin') 415edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 416edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef relpath(path, start=curdir): 417edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Return a relative version of a path""" 418edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 419edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not path: 420edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep raise ValueError("no path specified") 421edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 422edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep start_list = [x for x in abspath(start).split(sep) if x] 423edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep path_list = [x for x in abspath(path).split(sep) if x] 424edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 425edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Work out how much of the filepath is shared by start and path. 426edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep i = len(commonprefix([start_list, path_list])) 427edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 428edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep rel_list = [pardir] * (len(start_list)-i) + path_list[i:] 429edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not rel_list: 430edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return curdir 431edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return join(*rel_list) 432