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