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

Source Code for Module ntpath

  1  # Module 'ntpath' -- common operations on WinNT/Win95 pathnames 
  2  """Common pathname manipulations, WindowsNT/95 version. 
  3   
  4  Instead of importing this module directly, import os and refer to this 
  5  module as os.path. 
  6  """ 
  7   
  8  import os 
  9  import stat 
 10  import sys 
 11   
 12  __all__ = ["normcase","isabs","join","splitdrive","split","splitext", 
 13             "basename","dirname","commonprefix","getsize","getmtime", 
 14             "getatime","getctime", "islink","exists","lexists","isdir","isfile", 
 15             "ismount","walk","expanduser","expandvars","normpath","abspath", 
 16             "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", 
 17             "extsep","devnull","realpath","supports_unicode_filenames"] 
 18   
 19  # strings representing various path-related bits and pieces 
 20  curdir = '.' 
 21  pardir = '..' 
 22  extsep = '.' 
 23  sep = '\\' 
 24  pathsep = ';' 
 25  altsep = '/' 
 26  defpath = '.;C:\\bin' 
 27  if 'ce' in sys.builtin_module_names: 
 28      defpath = '\\Windows' 
 29  elif 'os2' in sys.builtin_module_names: 
 30      # OS/2 w/ VACPP 
 31      altsep = '/' 
 32  devnull = 'nul' 
 33   
 34  # Normalize the case of a pathname and map slashes to backslashes. 
 35  # Other normalizations (such as optimizing '../' away) are not done 
 36  # (this is done by normpath). 
 37   
38 -def normcase(s):
39 """Normalize case of pathname. 40 41 Makes all characters lowercase and all slashes into backslashes.""" 42 return s.replace("/", "\\").lower()
43 44 45 # Return whether a path is absolute. 46 # Trivial in Posix, harder on the Mac or MS-DOS. 47 # For DOS it is absolute if it starts with a slash or backslash (current 48 # volume), or if a pathname after the volume letter and colon / UNC resource 49 # starts with a slash or backslash. 50
51 -def isabs(s):
52 """Test whether a path is absolute""" 53 s = splitdrive(s)[1] 54 return s != '' and s[:1] in '/\\'
55 56 57 # Join two (or more) paths. 58
59 -def join(a, *p):
60 """Join two or more pathname components, inserting "\\" as needed""" 61 path = a 62 for b in p: 63 b_wins = 0 # set to 1 iff b makes path irrelevant 64 if path == "": 65 b_wins = 1 66 67 elif isabs(b): 68 # This probably wipes out path so far. However, it's more 69 # complicated if path begins with a drive letter: 70 # 1. join('c:', '/a') == 'c:/a' 71 # 2. join('c:/', '/a') == 'c:/a' 72 # But 73 # 3. join('c:/a', '/b') == '/b' 74 # 4. join('c:', 'd:/') = 'd:/' 75 # 5. join('c:/', 'd:/') = 'd:/' 76 if path[1:2] != ":" or b[1:2] == ":": 77 # Path doesn't start with a drive letter, or cases 4 and 5. 78 b_wins = 1 79 80 # Else path has a drive letter, and b doesn't but is absolute. 81 elif len(path) > 3 or (len(path) == 3 and 82 path[-1] not in "/\\"): 83 # case 3 84 b_wins = 1 85 86 if b_wins: 87 path = b 88 else: 89 # Join, and ensure there's a separator. 90 assert len(path) > 0 91 if path[-1] in "/\\": 92 if b and b[0] in "/\\": 93 path += b[1:] 94 else: 95 path += b 96 elif path[-1] == ":": 97 path += b 98 elif b: 99 if b[0] in "/\\": 100 path += b 101 else: 102 path += "\\" + b 103 else: 104 # path is not empty and does not end with a backslash, 105 # but b is empty; since, e.g., split('a/') produces 106 # ('a', ''), it's best if join() adds a backslash in 107 # this case. 108 path += '\\' 109 110 return path
111 112 113 # Split a path in a drive specification (a drive letter followed by a 114 # colon) and the path specification. 115 # It is always true that drivespec + pathspec == p
116 -def splitdrive(p):
117 """Split a pathname into drive and path specifiers. Returns a 2-tuple 118 "(drive,path)"; either part may be empty""" 119 if p[1:2] == ':': 120 return p[0:2], p[2:] 121 return '', p
122 123 124 # Parse UNC paths
125 -def splitunc(p):
126 """Split a pathname into UNC mount point and relative path specifiers. 127 128 Return a 2-tuple (unc, rest); either part may be empty. 129 If unc is not empty, it has the form '//host/mount' (or similar 130 using backslashes). unc+rest is always the input path. 131 Paths containing drive letters never have an UNC part. 132 """ 133 if p[1:2] == ':': 134 return '', p # Drive letter present 135 firstTwo = p[0:2] 136 if firstTwo == '//' or firstTwo == '\\\\': 137 # is a UNC path: 138 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter 139 # \\machine\mountpoint\directories... 140 # directory ^^^^^^^^^^^^^^^ 141 normp = normcase(p) 142 index = normp.find('\\', 2) 143 if index == -1: 144 ##raise RuntimeError, 'illegal UNC path: "' + p + '"' 145 return ("", p) 146 index = normp.find('\\', index + 1) 147 if index == -1: 148 index = len(p) 149 return p[:index], p[index:] 150 return '', p
151 152 153 # Split a path in head (everything up to the last '/') and tail (the 154 # rest). After the trailing '/' is stripped, the invariant 155 # join(head, tail) == p holds. 156 # The resulting head won't end in '/' unless it is the root. 157
158 -def split(p):
159 """Split a pathname. 160 161 Return tuple (head, tail) where tail is everything after the final slash. 162 Either part may be empty.""" 163 164 d, p = splitdrive(p) 165 # set i to index beyond p's last slash 166 i = len(p) 167 while i and p[i-1] not in '/\\': 168 i = i - 1 169 head, tail = p[:i], p[i:] # now tail has no slashes 170 # remove trailing slashes from head, unless it's all slashes 171 head2 = head 172 while head2 and head2[-1] in '/\\': 173 head2 = head2[:-1] 174 head = head2 or head 175 return d + head, tail
176 177 178 # Split a path in root and extension. 179 # The extension is everything starting at the last dot in the last 180 # pathname component; the root is everything before that. 181 # It is always true that root + ext == p. 182
183 -def splitext(p):
184 """Split the extension from a pathname. 185 186 Extension is everything from the last dot to the end. 187 Return (root, ext), either part may be empty.""" 188 189 i = p.rfind('.') 190 if i<=max(p.rfind('/'), p.rfind('\\')): 191 return p, '' 192 else: 193 return p[:i], p[i:]
194 195 196 # Return the tail (basename) part of a path. 197
198 -def basename(p):
199 """Returns the final component of a pathname""" 200 return split(p)[1]
201 202 203 # Return the head (dirname) part of a path. 204
205 -def dirname(p):
206 """Returns the directory component of a pathname""" 207 return split(p)[0]
208 209 210 # Return the longest prefix of all list elements. 211
212 -def commonprefix(m):
213 "Given a list of pathnames, returns the longest common leading component" 214 if not m: return '' 215 s1 = min(m) 216 s2 = max(m) 217 n = min(len(s1), len(s2)) 218 for i in xrange(n): 219 if s1[i] != s2[i]: 220 return s1[:i] 221 return s1[:n]
222 223 224 # Get size, mtime, atime of files. 225
226 -def getsize(filename):
227 """Return the size of a file, reported by os.stat()""" 228 return os.stat(filename).st_size
229
230 -def getmtime(filename):
231 """Return the last modification time of a file, reported by os.stat()""" 232 return os.stat(filename).st_mtime
233
234 -def getatime(filename):
235 """Return the last access time of a file, reported by os.stat()""" 236 return os.stat(filename).st_atime
237
238 -def getctime(filename):
239 """Return the creation time of a file, reported by os.stat().""" 240 return os.stat(filename).st_ctime
241 242 # Is a path a symbolic link? 243 # This will always return false on systems where posix.lstat doesn't exist. 244 248 249 250 # Does a path exist? 251
252 -def exists(path):
253 """Test whether a path exists""" 254 try: 255 st = os.stat(path) 256 except os.error: 257 return False 258 return True
259 260 lexists = exists 261 262 263 # Is a path a dos directory? 264 # This follows symbolic links, so both islink() and isdir() can be true 265 # for the same path. 266
267 -def isdir(path):
268 """Test whether a path is a directory""" 269 try: 270 st = os.stat(path) 271 except os.error: 272 return False 273 return stat.S_ISDIR(st.st_mode)
274 275 276 # Is a path a regular file? 277 # This follows symbolic links, so both islink() and isdir() can be true 278 # for the same path. 279
280 -def isfile(path):
281 """Test whether a path is a regular file""" 282 try: 283 st = os.stat(path) 284 except os.error: 285 return False 286 return stat.S_ISREG(st.st_mode)
287 288 289 # Is a path a mount point? Either a root (with or without drive letter) 290 # or an UNC path with at most a / or \ after the mount point. 291
292 -def ismount(path):
293 """Test whether a path is a mount point (defined as root of drive)""" 294 unc, rest = splitunc(path) 295 if unc: 296 return rest in ("", "/", "\\") 297 p = splitdrive(path)[1] 298 return len(p) == 1 and p[0] in '/\\'
299 300 301 # Directory tree walk. 302 # For each directory under top (including top itself, but excluding 303 # '.' and '..'), func(arg, dirname, filenames) is called, where 304 # dirname is the name of the directory and filenames is the list 305 # of files (and subdirectories etc.) in the directory. 306 # The func may modify the filenames list, to implement a filter, 307 # or to impose a different order of visiting. 308
309 -def walk(top, func, arg):
310 """Directory tree walk with callback function. 311 312 For each directory in the directory tree rooted at top (including top 313 itself, but excluding '.' and '..'), call func(arg, dirname, fnames). 314 dirname is the name of the directory, and fnames a list of the names of 315 the files and subdirectories in dirname (excluding '.' and '..'). func 316 may modify the fnames list in-place (e.g. via del or slice assignment), 317 and walk will only recurse into the subdirectories whose names remain in 318 fnames; this can be used to implement a filter, or to impose a specific 319 order of visiting. No semantics are defined for, or required of, arg, 320 beyond that arg is always passed to func. It can be used, e.g., to pass 321 a filename pattern, or a mutable object designed to accumulate 322 statistics. Passing None for arg is common.""" 323 324 try: 325 names = os.listdir(top) 326 except os.error: 327 return 328 func(arg, top, names) 329 exceptions = ('.', '..') 330 for name in names: 331 if name not in exceptions: 332 name = join(top, name) 333 if isdir(name): 334 walk(name, func, arg)
335 336 337 # Expand paths beginning with '~' or '~user'. 338 # '~' means $HOME; '~user' means that user's home directory. 339 # If the path doesn't begin with '~', or if the user or $HOME is unknown, 340 # the path is returned unchanged (leaving error reporting to whatever 341 # function is called with the expanded path as argument). 342 # See also module 'glob' for expansion of *, ? and [...] in pathnames. 343 # (A function should also be defined to do full *sh-style environment 344 # variable expansion.) 345
346 -def expanduser(path):
347 """Expand ~ and ~user constructs. 348 349 If user or $HOME is unknown, do nothing.""" 350 if path[:1] != '~': 351 return path 352 i, n = 1, len(path) 353 while i < n and path[i] not in '/\\': 354 i = i + 1 355 if i == 1: 356 if 'HOME' in os.environ: 357 userhome = os.environ['HOME'] 358 elif not 'HOMEPATH' in os.environ: 359 return path 360 else: 361 try: 362 drive = os.environ['HOMEDRIVE'] 363 except KeyError: 364 drive = '' 365 userhome = join(drive, os.environ['HOMEPATH']) 366 else: 367 return path 368 return userhome + path[i:]
369 370 371 # Expand paths containing shell variable substitutions. 372 # The following rules apply: 373 # - no expansion within single quotes 374 # - no escape character, except for '$$' which is translated into '$' 375 # - ${varname} is accepted. 376 # - varnames can be made out of letters, digits and the character '_' 377 # XXX With COMMAND.COM you can use any characters in a variable name, 378 # XXX except '^|<>='. 379
380 -def expandvars(path):
381 """Expand shell variables of form $var and ${var}. 382 383 Unknown variables are left unchanged.""" 384 if '$' not in path: 385 return path 386 import string 387 varchars = string.ascii_letters + string.digits + '_-' 388 res = '' 389 index = 0 390 pathlen = len(path) 391 while index < pathlen: 392 c = path[index] 393 if c == '\'': # no expansion within single quotes 394 path = path[index + 1:] 395 pathlen = len(path) 396 try: 397 index = path.index('\'') 398 res = res + '\'' + path[:index + 1] 399 except ValueError: 400 res = res + path 401 index = pathlen - 1 402 elif c == '$': # variable or '$$' 403 if path[index + 1:index + 2] == '$': 404 res = res + c 405 index = index + 1 406 elif path[index + 1:index + 2] == '{': 407 path = path[index+2:] 408 pathlen = len(path) 409 try: 410 index = path.index('}') 411 var = path[:index] 412 if var in os.environ: 413 res = res + os.environ[var] 414 except ValueError: 415 res = res + path 416 index = pathlen - 1 417 else: 418 var = '' 419 index = index + 1 420 c = path[index:index + 1] 421 while c != '' and c in varchars: 422 var = var + c 423 index = index + 1 424 c = path[index:index + 1] 425 if var in os.environ: 426 res = res + os.environ[var] 427 if c != '': 428 res = res + c 429 else: 430 res = res + c 431 index = index + 1 432 return res
433 434 435 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B. 436 # Previously, this function also truncated pathnames to 8+3 format, 437 # but as this module is called "ntpath", that's obviously wrong! 438
439 -def normpath(path):
440 """Normalize path, eliminating double slashes, etc.""" 441 path = path.replace("/", "\\") 442 prefix, path = splitdrive(path) 443 # We need to be careful here. If the prefix is empty, and the path starts 444 # with a backslash, it could either be an absolute path on the current 445 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It 446 # is therefore imperative NOT to collapse multiple backslashes blindly in 447 # that case. 448 # The code below preserves multiple backslashes when there is no drive 449 # letter. This means that the invalid filename \\\a\b is preserved 450 # unchanged, where a\\\b is normalised to a\b. It's not clear that there 451 # is any better behaviour for such edge cases. 452 if prefix == '': 453 # No drive letter - preserve initial backslashes 454 while path[:1] == "\\": 455 prefix = prefix + "\\" 456 path = path[1:] 457 else: 458 # We have a drive letter - collapse initial backslashes 459 if path.startswith("\\"): 460 prefix = prefix + "\\" 461 path = path.lstrip("\\") 462 comps = path.split("\\") 463 i = 0 464 while i < len(comps): 465 if comps[i] in ('.', ''): 466 del comps[i] 467 elif comps[i] == '..': 468 if i > 0 and comps[i-1] != '..': 469 del comps[i-1:i+1] 470 i -= 1 471 elif i == 0 and prefix.endswith("\\"): 472 del comps[i] 473 else: 474 i += 1 475 else: 476 i += 1 477 # If the path is now empty, substitute '.' 478 if not prefix and not comps: 479 comps.append('.') 480 return prefix + "\\".join(comps)
481 482 483 # Return an absolute path. 484 try: 485 from nt import _getfullpathname 486 487 except ImportError: # not running on Windows - mock up something sensible
488 - def abspath(path):
489 """Return the absolute version of a path.""" 490 if not isabs(path): 491 path = join(os.getcwd(), path) 492 return normpath(path)
493 494 else: # use native Windows method on Windows
495 - def abspath(path):
496 """Return the absolute version of a path.""" 497 498 if path: # Empty path must return current working directory. 499 try: 500 path = _getfullpathname(path) 501 except WindowsError: 502 pass # Bad path - return unchanged. 503 else: 504 path = os.getcwd() 505 return normpath(path)
506 507 # realpath is a no-op on systems without islink support 508 realpath = abspath 509 # Win9x family and earlier have no Unicode filename support. 510 supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and 511 sys.getwindowsversion()[3] >= 2) 512