Add PyErr_WarnEx()
[pytest.git] / Lib / ntpath.py
blob7a79b5322f169656cc4f928e3ea73d25dbb40a69
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","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"]
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'
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).
38 def normcase(s):
39 """Normalize case of pathname.
41 Makes all characters lowercase and all slashes into backslashes."""
42 return s.replace("/", "\\").lower()
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.
51 def isabs(s):
52 """Test whether a path is absolute"""
53 s = splitdrive(s)[1]
54 return s != '' and s[:1] in '/\\'
57 # Join two (or more) paths.
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
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
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
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 += '\\'
110 return path
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
124 # Parse UNC paths
125 def splitunc(p):
126 """Split a pathname into UNC mount point and relative path specifiers.
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.
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
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.
158 def split(p):
159 """Split a pathname.
161 Return tuple (head, tail) where tail is everything after the final slash.
162 Either part may be empty."""
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
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.
183 def splitext(p):
184 """Split the extension from a pathname.
186 Extension is everything from the last dot to the end.
187 Return (root, ext), either part may be empty."""
189 i = p.rfind('.')
190 if i<=max(p.rfind('/'), p.rfind('\\')):
191 return p, ''
192 else:
193 return p[:i], p[i:]
196 # Return the tail (basename) part of a path.
198 def basename(p):
199 """Returns the final component of a pathname"""
200 return split(p)[1]
203 # Return the head (dirname) part of a path.
205 def dirname(p):
206 """Returns the directory component of a pathname"""
207 return split(p)[0]
210 # Return the longest prefix of all list elements.
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]
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?
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
260 lexists = exists
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.
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)
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.
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)
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.
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 '/\\'
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.
309 def walk(top, func, arg):
310 """Directory tree walk with callback function.
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."""
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)
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.)
346 def expanduser(path):
347 """Expand ~ and ~user constructs.
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:]
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 '^|<>='.
380 def expandvars(path):
381 """Expand shell variables of form $var and ${var}.
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
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!
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)
483 # Return an absolute path.
484 try:
485 from nt import _getfullpathname
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)
494 else: # use native Windows method on Windows
495 def abspath(path):
496 """Return the absolute version of a path."""
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)
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)