Fix the availability statement for the spawn*() functions to reflect the
[python/dscho.git] / Lib / ntpath.py
blob21fadd0eb9bdfdaab624c5c67261c468332376ad
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
11 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
12 "basename","dirname","commonprefix","getsize","getmtime",
13 "getatime","islink","exists","isdir","isfile","ismount",
14 "walk","expanduser","expandvars","normpath","abspath","splitunc"]
16 # Normalize the case of a pathname and map slashes to backslashes.
17 # Other normalizations (such as optimizing '../' away) are not done
18 # (this is done by normpath).
20 def normcase(s):
21 """Normalize case of pathname.
23 Makes all characters lowercase and all slashes into backslashes."""
24 return s.replace("/", "\\").lower()
27 # Return whether a path is absolute.
28 # Trivial in Posix, harder on the Mac or MS-DOS.
29 # For DOS it is absolute if it starts with a slash or backslash (current
30 # volume), or if a pathname after the volume letter and colon / UNC resource
31 # starts with a slash or backslash.
33 def isabs(s):
34 """Test whether a path is absolute"""
35 s = splitdrive(s)[1]
36 return s != '' and s[:1] in '/\\'
39 # Join two (or more) paths.
41 def join(a, *p):
42 """Join two or more pathname components, inserting "\\" as needed"""
43 path = a
44 for b in p:
45 b_wins = 0 # set to 1 iff b makes path irrelevant
46 if path == "":
47 b_wins = 1
49 elif isabs(b):
50 # This probably wipes out path so far. However, it's more
51 # complicated if path begins with a drive letter:
52 # 1. join('c:', '/a') == 'c:/a'
53 # 2. join('c:/', '/a') == 'c:/a'
54 # But
55 # 3. join('c:/a', '/b') == '/b'
56 # 4. join('c:', 'd:/') = 'd:/'
57 # 5. join('c:/', 'd:/') = 'd:/'
58 if path[1:2] != ":" or b[1:2] == ":":
59 # Path doesn't start with a drive letter, or cases 4 and 5.
60 b_wins = 1
62 # Else path has a drive letter, and b doesn't but is absolute.
63 elif len(path) > 3 or (len(path) == 3 and
64 path[-1] not in "/\\"):
65 # case 3
66 b_wins = 1
68 if b_wins:
69 path = b
70 else:
71 # Join, and ensure there's a separator.
72 assert len(path) > 0
73 if path[-1] in "/\\":
74 if b and b[0] in "/\\":
75 path += b[1:]
76 else:
77 path += b
78 elif path[-1] == ":":
79 path += b
80 elif b:
81 if b[0] in "/\\":
82 path += b
83 else:
84 path += "\\" + b
85 else:
86 # path is not empty and does not end with a backslash,
87 # but b is empty; since, e.g., split('a/') produces
88 # ('a', ''), it's best if join() adds a backslash in
89 # this case.
90 path += '\\'
92 return path
95 # Split a path in a drive specification (a drive letter followed by a
96 # colon) and the path specification.
97 # It is always true that drivespec + pathspec == p
98 def splitdrive(p):
99 """Split a pathname into drive and path specifiers. Returns a 2-tuple
100 "(drive,path)"; either part may be empty"""
101 if p[1:2] == ':':
102 return p[0:2], p[2:]
103 return '', p
106 # Parse UNC paths
107 def splitunc(p):
108 """Split a pathname into UNC mount point and relative path specifiers.
110 Return a 2-tuple (unc, rest); either part may be empty.
111 If unc is not empty, it has the form '//host/mount' (or similar
112 using backslashes). unc+rest is always the input path.
113 Paths containing drive letters never have an UNC part.
115 if p[1:2] == ':':
116 return '', p # Drive letter present
117 firstTwo = p[0:2]
118 if firstTwo == '//' or firstTwo == '\\\\':
119 # is a UNC path:
120 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
121 # \\machine\mountpoint\directories...
122 # directory ^^^^^^^^^^^^^^^
123 normp = normcase(p)
124 index = normp.find('\\', 2)
125 if index == -1:
126 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
127 return ("", p)
128 index = normp.find('\\', index + 1)
129 if index == -1:
130 index = len(p)
131 return p[:index], p[index:]
132 return '', p
135 # Split a path in head (everything up to the last '/') and tail (the
136 # rest). After the trailing '/' is stripped, the invariant
137 # join(head, tail) == p holds.
138 # The resulting head won't end in '/' unless it is the root.
140 def split(p):
141 """Split a pathname.
143 Return tuple (head, tail) where tail is everything after the final slash.
144 Either part may be empty."""
146 d, p = splitdrive(p)
147 # set i to index beyond p's last slash
148 i = len(p)
149 while i and p[i-1] not in '/\\':
150 i = i - 1
151 head, tail = p[:i], p[i:] # now tail has no slashes
152 # remove trailing slashes from head, unless it's all slashes
153 head2 = head
154 while head2 and head2[-1] in '/\\':
155 head2 = head2[:-1]
156 head = head2 or head
157 return d + head, tail
160 # Split a path in root and extension.
161 # The extension is everything starting at the last dot in the last
162 # pathname component; the root is everything before that.
163 # It is always true that root + ext == p.
165 def splitext(p):
166 """Split the extension from a pathname.
168 Extension is everything from the last dot to the end.
169 Return (root, ext), either part may be empty."""
170 root, ext = '', ''
171 for c in p:
172 if c in ['/','\\']:
173 root, ext = root + ext + c, ''
174 elif c == '.':
175 if ext:
176 root, ext = root + ext, c
177 else:
178 ext = c
179 elif ext:
180 ext = ext + c
181 else:
182 root = root + c
183 return root, ext
186 # Return the tail (basename) part of a path.
188 def basename(p):
189 """Returns the final component of a pathname"""
190 return split(p)[1]
193 # Return the head (dirname) part of a path.
195 def dirname(p):
196 """Returns the directory component of a pathname"""
197 return split(p)[0]
200 # Return the longest prefix of all list elements.
202 def commonprefix(m):
203 "Given a list of pathnames, returns the longest common leading component"
204 if not m: return ''
205 prefix = m[0]
206 for item in m:
207 for i in range(len(prefix)):
208 if prefix[:i+1] != item[:i+1]:
209 prefix = prefix[:i]
210 if i == 0: return ''
211 break
212 return prefix
215 # Get size, mtime, atime of files.
217 def getsize(filename):
218 """Return the size of a file, reported by os.stat()"""
219 st = os.stat(filename)
220 return st[stat.ST_SIZE]
222 def getmtime(filename):
223 """Return the last modification time of a file, reported by os.stat()"""
224 st = os.stat(filename)
225 return st[stat.ST_MTIME]
227 def getatime(filename):
228 """Return the last access time of a file, reported by os.stat()"""
229 st = os.stat(filename)
230 return st[stat.ST_ATIME]
233 # Is a path a symbolic link?
234 # This will always return false on systems where posix.lstat doesn't exist.
236 def islink(path):
237 """Test for symbolic link. On WindowsNT/95 always returns false"""
238 return 0
241 # Does a path exist?
242 # This is false for dangling symbolic links.
244 def exists(path):
245 """Test whether a path exists"""
246 try:
247 st = os.stat(path)
248 except os.error:
249 return 0
250 return 1
253 # Is a path a dos directory?
254 # This follows symbolic links, so both islink() and isdir() can be true
255 # for the same path.
257 def isdir(path):
258 """Test whether a path is a directory"""
259 try:
260 st = os.stat(path)
261 except os.error:
262 return 0
263 return stat.S_ISDIR(st[stat.ST_MODE])
266 # Is a path a regular file?
267 # This follows symbolic links, so both islink() and isdir() can be true
268 # for the same path.
270 def isfile(path):
271 """Test whether a path is a regular file"""
272 try:
273 st = os.stat(path)
274 except os.error:
275 return 0
276 return stat.S_ISREG(st[stat.ST_MODE])
279 # Is a path a mount point? Either a root (with or without drive letter)
280 # or an UNC path with at most a / or \ after the mount point.
282 def ismount(path):
283 """Test whether a path is a mount point (defined as root of drive)"""
284 unc, rest = splitunc(path)
285 if unc:
286 return rest in ("", "/", "\\")
287 p = splitdrive(path)[1]
288 return len(p) == 1 and p[0] in '/\\'
291 # Directory tree walk.
292 # For each directory under top (including top itself, but excluding
293 # '.' and '..'), func(arg, dirname, filenames) is called, where
294 # dirname is the name of the directory and filenames is the list
295 # files files (and subdirectories etc.) in the directory.
296 # The func may modify the filenames list, to implement a filter,
297 # or to impose a different order of visiting.
299 def walk(top, func, arg):
300 """Directory tree walk with callback function.
302 For each directory in the directory tree rooted at top (including top
303 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
304 dirname is the name of the directory, and fnames a list of the names of
305 the files and subdirectories in dirname (excluding '.' and '..'). func
306 may modify the fnames list in-place (e.g. via del or slice assignment),
307 and walk will only recurse into the subdirectories whose names remain in
308 fnames; this can be used to implement a filter, or to impose a specific
309 order of visiting. No semantics are defined for, or required of, arg,
310 beyond that arg is always passed to func. It can be used, e.g., to pass
311 a filename pattern, or a mutable object designed to accumulate
312 statistics. Passing None for arg is common."""
314 try:
315 names = os.listdir(top)
316 except os.error:
317 return
318 func(arg, top, names)
319 exceptions = ('.', '..')
320 for name in names:
321 if name not in exceptions:
322 name = join(top, name)
323 if isdir(name):
324 walk(name, func, arg)
327 # Expand paths beginning with '~' or '~user'.
328 # '~' means $HOME; '~user' means that user's home directory.
329 # If the path doesn't begin with '~', or if the user or $HOME is unknown,
330 # the path is returned unchanged (leaving error reporting to whatever
331 # function is called with the expanded path as argument).
332 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
333 # (A function should also be defined to do full *sh-style environment
334 # variable expansion.)
336 def expanduser(path):
337 """Expand ~ and ~user constructs.
339 If user or $HOME is unknown, do nothing."""
340 if path[:1] != '~':
341 return path
342 i, n = 1, len(path)
343 while i < n and path[i] not in '/\\':
344 i = i + 1
345 if i == 1:
346 if os.environ.has_key('HOME'):
347 userhome = os.environ['HOME']
348 elif not os.environ.has_key('HOMEPATH'):
349 return path
350 else:
351 try:
352 drive = os.environ['HOMEDRIVE']
353 except KeyError:
354 drive = ''
355 userhome = join(drive, os.environ['HOMEPATH'])
356 else:
357 return path
358 return userhome + path[i:]
361 # Expand paths containing shell variable substitutions.
362 # The following rules apply:
363 # - no expansion within single quotes
364 # - no escape character, except for '$$' which is translated into '$'
365 # - ${varname} is accepted.
366 # - varnames can be made out of letters, digits and the character '_'
367 # XXX With COMMAND.COM you can use any characters in a variable name,
368 # XXX except '^|<>='.
370 def expandvars(path):
371 """Expand shell variables of form $var and ${var}.
373 Unknown variables are left unchanged."""
374 if '$' not in path:
375 return path
376 import string
377 varchars = string.ascii_letters + string.digits + '_-'
378 res = ''
379 index = 0
380 pathlen = len(path)
381 while index < pathlen:
382 c = path[index]
383 if c == '\'': # no expansion within single quotes
384 path = path[index + 1:]
385 pathlen = len(path)
386 try:
387 index = path.index('\'')
388 res = res + '\'' + path[:index + 1]
389 except ValueError:
390 res = res + path
391 index = pathlen - 1
392 elif c == '$': # variable or '$$'
393 if path[index + 1:index + 2] == '$':
394 res = res + c
395 index = index + 1
396 elif path[index + 1:index + 2] == '{':
397 path = path[index+2:]
398 pathlen = len(path)
399 try:
400 index = path.index('}')
401 var = path[:index]
402 if os.environ.has_key(var):
403 res = res + os.environ[var]
404 except ValueError:
405 res = res + path
406 index = pathlen - 1
407 else:
408 var = ''
409 index = index + 1
410 c = path[index:index + 1]
411 while c != '' and c in varchars:
412 var = var + c
413 index = index + 1
414 c = path[index:index + 1]
415 if os.environ.has_key(var):
416 res = res + os.environ[var]
417 if c != '':
418 res = res + c
419 else:
420 res = res + c
421 index = index + 1
422 return res
425 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
426 # Previously, this function also truncated pathnames to 8+3 format,
427 # but as this module is called "ntpath", that's obviously wrong!
429 def normpath(path):
430 """Normalize path, eliminating double slashes, etc."""
431 path = path.replace("/", "\\")
432 prefix, path = splitdrive(path)
433 while path[:1] == "\\":
434 prefix = prefix + "\\"
435 path = path[1:]
436 comps = path.split("\\")
437 i = 0
438 while i < len(comps):
439 if comps[i] in ('.', ''):
440 del comps[i]
441 elif comps[i] == '..':
442 if i > 0 and comps[i-1] != '..':
443 del comps[i-1:i+1]
444 i -= 1
445 elif i == 0 and prefix.endswith("\\"):
446 del comps[i]
447 else:
448 i += 1
449 else:
450 i += 1
451 # If the path is now empty, substitute '.'
452 if not prefix and not comps:
453 comps.append('.')
454 return prefix + "\\".join(comps)
457 # Return an absolute path.
458 def abspath(path):
459 """Return the absolute version of a path"""
460 if path: # Empty path must return current working directory.
461 from nt import _getfullpathname
462 try:
463 path = _getfullpathname(path)
464 except WindowsError:
465 pass # Bad path - return unchanged.
466 else:
467 path = os.getcwd()
468 return normpath(path)
470 # realpath is a no-op on systems without islink support
471 realpath = abspath