Module posixpath
[hide private]
[frames] | no frames]

Source Code for Module posixpath

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