0001 """Common operations on Posix pathnames. 0002 0003 Instead of importing this module directly, import os and refer to 0004 this module as os.path. The "os.path" name is an alias for this 0005 module on Posix systems; on other systems (e.g. Mac, Windows), 0006 os.path provides the same operations in a manner specific to that 0007 platform, and is an alias to another module (e.g. macpath, ntpath). 0008 0009 Some of this can actually be useful on non-Posix systems too, e.g. 0010 for manipulation of the pathname component of URLs. 0011 """ 0012 0013 import os 0014 import stat 0015 0016 __all__ = ["normcase","isabs","join","splitdrive","split","splitext", 0017 "basename","dirname","commonprefix","getsize","getmtime", 0018 "getatime","getctime","islink","exists","isdir","isfile","ismount", 0019 "walk","expanduser","expandvars","normpath","abspath", 0020 "samefile","sameopenfile","samestat", 0021 "curdir","pardir","sep","pathsep","defpath","altsep","extsep", 0022 "devnull","realpath","supports_unicode_filenames"] 0023 0024 # strings representing various path-related bits and pieces 0025 curdir = '.' 0026 pardir = '..' 0027 extsep = '.' 0028 sep = '/' 0029 pathsep = ':' 0030 defpath = ':/bin:/usr/bin' 0031 altsep = None 0032 devnull = '/dev/null' 0033 0034 # Normalize the case of a pathname. Trivial in Posix, string.lower on Mac. 0035 # On MS-DOS this may also turn slashes into backslashes; however, other 0036 # normalizations (such as optimizing '../' away) are not allowed 0037 # (another function should be defined to do that). 0038 0039 def normcase(s): 0040 """Normalize case of pathname. Has no effect under Posix""" 0041 return s 0042 0043 0044 # Return whether a path is absolute. 0045 # Trivial in Posix, harder on the Mac or MS-DOS. 0046 0047 def isabs(s): 0048 """Test whether a path is absolute""" 0049 return s.startswith('/') 0050 0051 0052 # Join pathnames. 0053 # Ignore the previous parts if a part is absolute. 0054 # Insert a '/' unless the first part is empty or already ends in '/'. 0055 0056 def join(a, *p): 0057 """Join two or more pathname components, inserting '/' as needed""" 0058 path = a 0059 for b in p: 0060 if b.startswith('/'): 0061 path = b 0062 elif path == '' or path.endswith('/'): 0063 path += b 0064 else: 0065 path += '/' + b 0066 return path 0067 0068 0069 # Split a path in head (everything up to the last '/') and tail (the 0070 # rest). If the path ends in '/', tail will be empty. If there is no 0071 # '/' in the path, head will be empty. 0072 # Trailing '/'es are stripped from head unless it is the root. 0073 0074 def split(p): 0075 """Split a pathname. Returns tuple "(head, tail)" where "tail" is 0076 everything after the final slash. Either part may be empty.""" 0077 i = p.rfind('/') + 1 0078 head, tail = p[:i], p[i:] 0079 if head and head != '/'*len(head): 0080 head = head.rstrip('/') 0081 return head, tail 0082 0083 0084 # Split a path in root and extension. 0085 # The extension is everything starting at the last dot in the last 0086 # pathname component; the root is everything before that. 0087 # It is always true that root + ext == p. 0088 0089 def splitext(p): 0090 """Split the extension from a pathname. Extension is everything from the 0091 last dot to the end. Returns "(root, ext)", either part may be empty.""" 0092 i = p.rfind('.') 0093 if i<=p.rfind('/'): 0094 return p, '' 0095 else: 0096 return p[:i], p[i:] 0097 0098 0099 # Split a pathname into a drive specification and the rest of the 0100 # path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. 0101 0102 def splitdrive(p): 0103 """Split a pathname into drive and path. On Posix, drive is always 0104 empty.""" 0105 return '', p 0106 0107 0108 # Return the tail (basename) part of a path. 0109 0110 def basename(p): 0111 """Returns the final component of a pathname""" 0112 return split(p)[1] 0113 0114 0115 # Return the head (dirname) part of a path. 0116 0117 def dirname(p): 0118 """Returns the directory component of a pathname""" 0119 return split(p)[0] 0120 0121 0122 # Return the longest prefix of all list elements. 0123 0124 def commonprefix(m): 0125 "Given a list of pathnames, returns the longest common leading component" 0126 if not m: return '' 0127 s1 = min(m) 0128 s2 = max(m) 0129 n = min(len(s1), len(s2)) 0130 for i in xrange(n): 0131 if s1[i] != s2[i]: 0132 return s1[:i] 0133 return s1[:n] 0134 0135 # Get size, mtime, atime of files. 0136 0137 def getsize(filename): 0138 """Return the size of a file, reported by os.stat().""" 0139 return os.stat(filename).st_size 0140 0141 def getmtime(filename): 0142 """Return the last modification time of a file, reported by os.stat().""" 0143 return os.stat(filename).st_mtime 0144 0145 def getatime(filename): 0146 """Return the last access time of a file, reported by os.stat().""" 0147 return os.stat(filename).st_atime 0148 0149 def getctime(filename): 0150 """Return the metadata change time of a file, reported by os.stat().""" 0151 return os.stat(filename).st_ctime 0152 0153 # Is a path a symbolic link? 0154 # This will always return false on systems where os.lstat doesn't exist. 0155 0156 def islink(path): 0157 """Test whether a path is a symbolic link""" 0158 try: 0159 st = os.lstat(path) 0160 except (os.error, AttributeError): 0161 return False 0162 return stat.S_ISLNK(st.st_mode) 0163 0164 0165 # Does a path exist? 0166 # This is false for dangling symbolic links. 0167 0168 def exists(path): 0169 """Test whether a path exists. Returns False for broken symbolic links""" 0170 try: 0171 st = os.stat(path) 0172 except os.error: 0173 return False 0174 return True 0175 0176 0177 # Being true for dangling symbolic links is also useful. 0178 0179 def lexists(path): 0180 """Test whether a path exists. Returns True for broken symbolic links""" 0181 try: 0182 st = os.lstat(path) 0183 except os.error: 0184 return False 0185 return True 0186 0187 0188 # Is a path a directory? 0189 # This follows symbolic links, so both islink() and isdir() can be true 0190 # for the same path. 0191 0192 def isdir(path): 0193 """Test whether a path is a directory""" 0194 try: 0195 st = os.stat(path) 0196 except os.error: 0197 return False 0198 return stat.S_ISDIR(st.st_mode) 0199 0200 0201 # Is a path a regular file? 0202 # This follows symbolic links, so both islink() and isfile() can be true 0203 # for the same path. 0204 0205 def isfile(path): 0206 """Test whether a path is a regular file""" 0207 try: 0208 st = os.stat(path) 0209 except os.error: 0210 return False 0211 return stat.S_ISREG(st.st_mode) 0212 0213 0214 # Are two filenames really pointing to the same file? 0215 0216 def samefile(f1, f2): 0217 """Test whether two pathnames reference the same actual file""" 0218 s1 = os.stat(f1) 0219 s2 = os.stat(f2) 0220 return samestat(s1, s2) 0221 0222 0223 # Are two open files really referencing the same file? 0224 # (Not necessarily the same file descriptor!) 0225 0226 def sameopenfile(fp1, fp2): 0227 """Test whether two open file objects reference the same file""" 0228 s1 = os.fstat(fp1) 0229 s2 = os.fstat(fp2) 0230 return samestat(s1, s2) 0231 0232 0233 # Are two stat buffers (obtained from stat, fstat or lstat) 0234 # describing the same file? 0235 0236 def samestat(s1, s2): 0237 """Test whether two stat buffers reference the same file""" 0238 return s1.st_ino == s2.st_ino and \ 0239 s1.st_dev == s2.st_dev 0240 0241 0242 # Is a path a mount point? 0243 # (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) 0244 0245 def ismount(path): 0246 """Test whether a path is a mount point""" 0247 try: 0248 s1 = os.stat(path) 0249 s2 = os.stat(join(path, '..')) 0250 except os.error: 0251 return False # It doesn't exist -- so not a mount point :-) 0252 dev1 = s1.st_dev 0253 dev2 = s2.st_dev 0254 if dev1 != dev2: 0255 return True # path/.. on a different device as path 0256 ino1 = s1.st_ino 0257 ino2 = s2.st_ino 0258 if ino1 == ino2: 0259 return True # path/.. is the same i-node as path 0260 return False 0261 0262 0263 # Directory tree walk. 0264 # For each directory under top (including top itself, but excluding 0265 # '.' and '..'), func(arg, dirname, filenames) is called, where 0266 # dirname is the name of the directory and filenames is the list 0267 # of files (and subdirectories etc.) in the directory. 0268 # The func may modify the filenames list, to implement a filter, 0269 # or to impose a different order of visiting. 0270 0271 def walk(top, func, arg): 0272 """Directory tree walk with callback function. 0273 0274 For each directory in the directory tree rooted at top (including top 0275 itself, but excluding '.' and '..'), call func(arg, dirname, fnames). 0276 dirname is the name of the directory, and fnames a list of the names of 0277 the files and subdirectories in dirname (excluding '.' and '..'). func 0278 may modify the fnames list in-place (e.g. via del or slice assignment), 0279 and walk will only recurse into the subdirectories whose names remain in 0280 fnames; this can be used to implement a filter, or to impose a specific 0281 order of visiting. No semantics are defined for, or required of, arg, 0282 beyond that arg is always passed to func. It can be used, e.g., to pass 0283 a filename pattern, or a mutable object designed to accumulate 0284 statistics. Passing None for arg is common.""" 0285 0286 try: 0287 names = os.listdir(top) 0288 except os.error: 0289 return 0290 func(arg, top, names) 0291 for name in names: 0292 name = join(top, name) 0293 try: 0294 st = os.lstat(name) 0295 except os.error: 0296 continue 0297 if stat.S_ISDIR(st.st_mode): 0298 walk(name, func, arg) 0299 0300 0301 # Expand paths beginning with '~' or '~user'. 0302 # '~' means $HOME; '~user' means that user's home directory. 0303 # If the path doesn't begin with '~', or if the user or $HOME is unknown, 0304 # the path is returned unchanged (leaving error reporting to whatever 0305 # function is called with the expanded path as argument). 0306 # See also module 'glob' for expansion of *, ? and [...] in pathnames. 0307 # (A function should also be defined to do full *sh-style environment 0308 # variable expansion.) 0309 0310 def expanduser(path): 0311 """Expand ~ and ~user constructions. If user or $HOME is unknown, 0312 do nothing.""" 0313 if not path.startswith('~'): 0314 return path 0315 i = path.find('/', 1) 0316 if i < 0: 0317 i = len(path) 0318 if i == 1: 0319 if 'HOME' not in os.environ: 0320 import pwd 0321 userhome = pwd.getpwuid(os.getuid()).pw_dir 0322 else: 0323 userhome = os.environ['HOME'] 0324 else: 0325 import pwd 0326 try: 0327 pwent = pwd.getpwnam(path[1:i]) 0328 except KeyError: 0329 return path 0330 userhome = pwent.pw_dir 0331 if userhome.endswith('/'): 0332 i += 1 0333 return userhome + path[i:] 0334 0335 0336 # Expand paths containing shell variable substitutions. 0337 # This expands the forms $variable and ${variable} only. 0338 # Non-existent variables are left unchanged. 0339 0340 _varprog = None 0341 0342 def expandvars(path): 0343 """Expand shell variables of form $var and ${var}. Unknown variables 0344 are left unchanged.""" 0345 global _varprog 0346 if '$' not in path: 0347 return path 0348 if not _varprog: 0349 import re 0350 _varprog = re.compile(r'\$(\w+|\{[^}]*\})') 0351 i = 0 0352 while True: 0353 m = _varprog.search(path, i) 0354 if not m: 0355 break 0356 i, j = m.span(0) 0357 name = m.group(1) 0358 if name.startswith('{') and name.endswith('}'): 0359 name = name[1:-1] 0360 if name in os.environ: 0361 tail = path[j:] 0362 path = path[:i] + os.environ[name] 0363 i = len(path) 0364 path += tail 0365 else: 0366 i = j 0367 return path 0368 0369 0370 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. 0371 # It should be understood that this may change the meaning of the path 0372 # if it contains symbolic links! 0373 0374 def normpath(path): 0375 """Normalize path, eliminating double slashes, etc.""" 0376 if path == '': 0377 return '.' 0378 initial_slashes = path.startswith('/') 0379 # POSIX allows one or two initial slashes, but treats three or more 0380 # as single slash. 0381 if (initial_slashes and 0382 path.startswith('//') and not path.startswith('///')): 0383 initial_slashes = 2 0384 comps = path.split('/') 0385 new_comps = [] 0386 for comp in comps: 0387 if comp in ('', '.'): 0388 continue 0389 if (comp != '..' or (not initial_slashes and not new_comps) or 0390 (new_comps and new_comps[-1] == '..')): 0391 new_comps.append(comp) 0392 elif new_comps: 0393 new_comps.pop() 0394 comps = new_comps 0395 path = '/'.join(comps) 0396 if initial_slashes: 0397 path = '/'*initial_slashes + path 0398 return path or '.' 0399 0400 0401 def abspath(path): 0402 """Return an absolute path.""" 0403 if not isabs(path): 0404 path = join(os.getcwd(), path) 0405 return normpath(path) 0406 0407 0408 # Return a canonical path (i.e. the absolute location of a file on the 0409 # filesystem). 0410 0411 def realpath(filename): 0412 """Return the canonical path of the specified filename, eliminating any 0413 symbolic links encountered in the path.""" 0414 if isabs(filename): 0415 bits = ['/'] + filename.split('/')[1:] 0416 else: 0417 bits = filename.split('/') 0418 0419 for i in range(2, len(bits)+1): 0420 component = join(*bits[0:i]) 0421 # Resolve symbolic links. 0422 if islink(component): 0423 resolved = _resolve_link(component) 0424 if resolved is None: 0425 # Infinite loop -- return original component + rest of the path 0426 return abspath(join(*([component] + bits[i:]))) 0427 else: 0428 newpath = join(*([resolved] + bits[i:])) 0429 return realpath(newpath) 0430 0431 return abspath(filename) 0432 0433 0434 def _resolve_link(path): 0435 """Internal helper function. Takes a path and follows symlinks 0436 until we either arrive at something that isn't a symlink, or 0437 encounter a path we've seen before (meaning that there's a loop). 0438 """ 0439 paths_seen = [] 0440 while islink(path): 0441 if path in paths_seen: 0442 # Already seen this path, so we must have a symlink loop 0443 return None 0444 paths_seen.append(path) 0445 # Resolve where the link points to 0446 resolved = os.readlink(path) 0447 if not isabs(resolved): 0448 dir = dirname(path) 0449 path = normpath(join(dir, resolved)) 0450 else: 0451 path = normpath(resolved) 0452 return path 0453 0454 supports_unicode_filenames = False 0455
Generated by PyXR 0.9.4