blob: 04f0b2d4b35a0b9f6a4908790903a5920a70e2da [file] [log] [blame]
Guido van Rossum15e22e11997-12-05 19:03:01 +00001# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
Tim Peters2344fae2001-01-15 00:50:52 +00002"""Common pathname manipulations, WindowsNT/95 version.
Guido van Rossum534972b1999-02-03 17:20:50 +00003
4Instead of importing this module directly, import os and refer to this
5module as os.path.
Guido van Rossum15e22e11997-12-05 19:03:01 +00006"""
Guido van Rossum555915a1994-02-24 11:32:59 +00007
8import os
Mark Hammond8696ebc2002-10-08 02:44:31 +00009import sys
Christian Heimesc5f05e42008-02-23 17:40:11 +000010import stat
Martin v. Löwis05c075d2007-03-07 11:04:33 +000011import genericpath
Benjamin Peterson0893a0a2008-05-09 00:27:01 +000012import warnings
13
Jack Diederich7b604642006-08-26 18:42:06 +000014from genericpath import *
Skip Montanaro4d5d5bf2000-07-13 01:01:03 +000015
Skip Montanaro269b83b2001-02-06 01:07:02 +000016__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
17 "basename","dirname","commonprefix","getsize","getmtime",
Georg Brandlf0de6a12005-08-22 18:02:59 +000018 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
19 "ismount","walk","expanduser","expandvars","normpath","abspath",
20 "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
Collin Winter6f187742007-03-16 22:16:08 +000021 "extsep","devnull","realpath","supports_unicode_filenames","relpath"]
Guido van Rossum555915a1994-02-24 11:32:59 +000022
Skip Montanaro117910d2003-02-14 19:35:31 +000023# strings representing various path-related bits and pieces
24curdir = '.'
25pardir = '..'
26extsep = '.'
27sep = '\\'
28pathsep = ';'
Skip Montanaro9ddac3e2003-03-28 22:23:24 +000029altsep = '/'
Andrew MacIntyre437966c2003-02-17 09:17:50 +000030defpath = '.;C:\\bin'
Skip Montanaro117910d2003-02-14 19:35:31 +000031if 'ce' in sys.builtin_module_names:
32 defpath = '\\Windows'
33elif 'os2' in sys.builtin_module_names:
Andrew MacIntyre437966c2003-02-17 09:17:50 +000034 # OS/2 w/ VACPP
Skip Montanaro117910d2003-02-14 19:35:31 +000035 altsep = '/'
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000036devnull = 'nul'
Skip Montanaro117910d2003-02-14 19:35:31 +000037
Guido van Rossume2ad88c1997-08-12 14:46:58 +000038# Normalize the case of a pathname and map slashes to backslashes.
39# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000040# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000041
Guido van Rossum555915a1994-02-24 11:32:59 +000042def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000043 """Normalize case of pathname.
44
Guido van Rossum534972b1999-02-03 17:20:50 +000045 Makes all characters lowercase and all slashes into backslashes."""
Fred Drakeb4e460a2000-09-28 16:25:20 +000046 return s.replace("/", "\\").lower()
Guido van Rossum555915a1994-02-24 11:32:59 +000047
Guido van Rossum77e1db31997-06-02 23:11:57 +000048
Fred Drakeef0b5dd2000-02-17 17:30:40 +000049# Return whether a path is absolute.
Guido van Rossum555915a1994-02-24 11:32:59 +000050# Trivial in Posix, harder on the Mac or MS-DOS.
51# For DOS it is absolute if it starts with a slash or backslash (current
Guido van Rossum534972b1999-02-03 17:20:50 +000052# volume), or if a pathname after the volume letter and colon / UNC resource
53# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000054
55def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000056 """Test whether a path is absolute"""
57 s = splitdrive(s)[1]
58 return s != '' and s[:1] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +000059
60
Guido van Rossum77e1db31997-06-02 23:11:57 +000061# Join two (or more) paths.
62
Barry Warsaw384d2491997-02-18 21:53:25 +000063def join(a, *p):
Georg Brandlda5f16a2007-08-23 21:27:57 +000064 """Join two or more pathname components, inserting "\\" as needed.
65 If any component is an absolute path, all previous path components
66 will be discarded."""
Guido van Rossum15e22e11997-12-05 19:03:01 +000067 path = a
68 for b in p:
Tim Peters33dc0a12001-07-27 08:09:54 +000069 b_wins = 0 # set to 1 iff b makes path irrelevant
70 if path == "":
71 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000072
Tim Peters33dc0a12001-07-27 08:09:54 +000073 elif isabs(b):
74 # This probably wipes out path so far. However, it's more
75 # complicated if path begins with a drive letter:
76 # 1. join('c:', '/a') == 'c:/a'
77 # 2. join('c:/', '/a') == 'c:/a'
78 # But
79 # 3. join('c:/a', '/b') == '/b'
80 # 4. join('c:', 'd:/') = 'd:/'
81 # 5. join('c:/', 'd:/') = 'd:/'
82 if path[1:2] != ":" or b[1:2] == ":":
83 # Path doesn't start with a drive letter, or cases 4 and 5.
84 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000085
Tim Peters33dc0a12001-07-27 08:09:54 +000086 # Else path has a drive letter, and b doesn't but is absolute.
87 elif len(path) > 3 or (len(path) == 3 and
88 path[-1] not in "/\\"):
89 # case 3
90 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000091
Tim Peters33dc0a12001-07-27 08:09:54 +000092 if b_wins:
93 path = b
94 else:
95 # Join, and ensure there's a separator.
96 assert len(path) > 0
97 if path[-1] in "/\\":
98 if b and b[0] in "/\\":
99 path += b[1:]
100 else:
101 path += b
102 elif path[-1] == ":":
103 path += b
104 elif b:
105 if b[0] in "/\\":
106 path += b
107 else:
108 path += "\\" + b
Tim Peters6a3e5f12001-11-05 21:25:02 +0000109 else:
110 # path is not empty and does not end with a backslash,
111 # but b is empty; since, e.g., split('a/') produces
112 # ('a', ''), it's best if join() adds a backslash in
113 # this case.
114 path += '\\'
Tim Peters1bdd0f22001-07-19 17:18:18 +0000115
Guido van Rossum15e22e11997-12-05 19:03:01 +0000116 return path
Guido van Rossum555915a1994-02-24 11:32:59 +0000117
118
119# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000120# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000121# It is always true that drivespec + pathspec == p
122def splitdrive(p):
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000123 """Split a pathname into drive and path specifiers. Returns a 2-tuple
124"(drive,path)"; either part may be empty"""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000125 if p[1:2] == ':':
126 return p[0:2], p[2:]
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000127 return '', p
128
129
130# Parse UNC paths
131def splitunc(p):
132 """Split a pathname into UNC mount point and relative path specifiers.
133
134 Return a 2-tuple (unc, rest); either part may be empty.
135 If unc is not empty, it has the form '//host/mount' (or similar
136 using backslashes). unc+rest is always the input path.
137 Paths containing drive letters never have an UNC part.
138 """
Serhiy Storchakadd5a46c2013-12-16 15:15:29 +0200139 #if p[1:2] == ':':
140 #return '', p # Drive letter present
141 #firstTwo = p[0:2]
142 #if firstTwo == '//' or firstTwo == '\\\\':
143 ## is a UNC path:
144 ## vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
145 ## \\machine\mountpoint\directories...
146 ## directory ^^^^^^^^^^^^^^^
147 #normp = normcase(p)
148 #index = normp.find('\\', 2)
149 #if index == -1:
150 ###raise RuntimeError, 'illegal UNC path: "' + p + '"'
151 #return ("", p)
152 #index = normp.find('\\', index + 1)
153 #if index == -1:
154 #index = len(p)
155 #return p[:index], p[index:]
156 #return '', p
157
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000158 if p[1:2] == ':':
159 return '', p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000160 firstTwo = p[0:2]
161 if firstTwo == '//' or firstTwo == '\\\\':
162 # is a UNC path:
163 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
164 # \\machine\mountpoint\directories...
165 # directory ^^^^^^^^^^^^^^^
Serhiy Storchakadd5a46c2013-12-16 15:15:29 +0200166 normp = p.replace('\\', '/')
167 index = normp.find('/', 2)
168 if index <= 2:
169 return '', p
170 index2 = normp.find('/', index + 1)
171 # a UNC path can't have two slashes in a row
172 # (after the initial two)
173 if index2 == index + 1:
174 return '', p
175 if index2 == -1:
176 index2 = len(p)
177 return p[:index2], p[index2:]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000178 return '', p
Guido van Rossum555915a1994-02-24 11:32:59 +0000179
180
181# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000182# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000183# join(head, tail) == p holds.
184# The resulting head won't end in '/' unless it is the root.
185
186def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000187 """Split a pathname.
188
189 Return tuple (head, tail) where tail is everything after the final slash.
190 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000191
Guido van Rossum15e22e11997-12-05 19:03:01 +0000192 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000193 # set i to index beyond p's last slash
194 i = len(p)
195 while i and p[i-1] not in '/\\':
196 i = i - 1
197 head, tail = p[:i], p[i:] # now tail has no slashes
198 # remove trailing slashes from head, unless it's all slashes
199 head2 = head
200 while head2 and head2[-1] in '/\\':
201 head2 = head2[:-1]
202 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000203 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000204
205
206# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000207# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000208# pathname component; the root is everything before that.
209# It is always true that root + ext == p.
210
211def splitext(p):
Martin v. Löwis05c075d2007-03-07 11:04:33 +0000212 return genericpath._splitext(p, sep, altsep, extsep)
213splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000214
215
216# Return the tail (basename) part of a path.
217
218def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000219 """Returns the final component of a pathname"""
220 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000221
222
223# Return the head (dirname) part of a path.
224
225def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000226 """Returns the directory component of a pathname"""
227 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000228
Guido van Rossum555915a1994-02-24 11:32:59 +0000229# Is a path a symbolic link?
230# This will always return false on systems where posix.lstat doesn't exist.
231
232def islink(path):
Jack Diederich7b604642006-08-26 18:42:06 +0000233 """Test for symbolic link.
234 On WindowsNT/95 and OS/2 always returns false
235 """
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000236 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000237
Jack Diederich7b604642006-08-26 18:42:06 +0000238# alias exists to lexists
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000239lexists = exists
240
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000241# Is a path a mount point? Either a root (with or without drive letter)
242# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000243
244def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000245 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000246 unc, rest = splitunc(path)
247 if unc:
248 return rest in ("", "/", "\\")
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000249 p = splitdrive(path)[1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000250 return len(p) == 1 and p[0] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +0000251
252
253# Directory tree walk.
254# For each directory under top (including top itself, but excluding
255# '.' and '..'), func(arg, dirname, filenames) is called, where
256# dirname is the name of the directory and filenames is the list
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +0000257# of files (and subdirectories etc.) in the directory.
Guido van Rossum555915a1994-02-24 11:32:59 +0000258# The func may modify the filenames list, to implement a filter,
259# or to impose a different order of visiting.
260
261def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000262 """Directory tree walk with callback function.
Guido van Rossum534972b1999-02-03 17:20:50 +0000263
Tim Peterscf5e6a42001-10-10 04:16:20 +0000264 For each directory in the directory tree rooted at top (including top
265 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
266 dirname is the name of the directory, and fnames a list of the names of
267 the files and subdirectories in dirname (excluding '.' and '..'). func
268 may modify the fnames list in-place (e.g. via del or slice assignment),
269 and walk will only recurse into the subdirectories whose names remain in
270 fnames; this can be used to implement a filter, or to impose a specific
271 order of visiting. No semantics are defined for, or required of, arg,
272 beyond that arg is always passed to func. It can be used, e.g., to pass
273 a filename pattern, or a mutable object designed to accumulate
274 statistics. Passing None for arg is common."""
Philip Jenveyd846f1d2009-05-08 02:28:39 +0000275 warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",
276 stacklevel=2)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000277 try:
278 names = os.listdir(top)
279 except os.error:
280 return
281 func(arg, top, names)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000282 for name in names:
Georg Brandle2a902c2008-01-06 14:17:36 +0000283 name = join(top, name)
284 if isdir(name):
285 walk(name, func, arg)
Guido van Rossum555915a1994-02-24 11:32:59 +0000286
287
288# Expand paths beginning with '~' or '~user'.
289# '~' means $HOME; '~user' means that user's home directory.
290# If the path doesn't begin with '~', or if the user or $HOME is unknown,
291# the path is returned unchanged (leaving error reporting to whatever
292# function is called with the expanded path as argument).
293# See also module 'glob' for expansion of *, ? and [...] in pathnames.
294# (A function should also be defined to do full *sh-style environment
295# variable expansion.)
296
297def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000298 """Expand ~ and ~user constructs.
299
300 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000301 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000302 return path
303 i, n = 1, len(path)
304 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000305 i = i + 1
Georg Brandl03b90d82007-03-13 22:07:36 +0000306
307 if 'HOME' in os.environ:
308 userhome = os.environ['HOME']
309 elif 'USERPROFILE' in os.environ:
310 userhome = os.environ['USERPROFILE']
311 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000312 return path
Georg Brandl03b90d82007-03-13 22:07:36 +0000313 else:
314 try:
315 drive = os.environ['HOMEDRIVE']
316 except KeyError:
317 drive = ''
318 userhome = join(drive, os.environ['HOMEPATH'])
319
320 if i != 1: #~user
321 userhome = join(dirname(userhome), path[1:i])
322
Guido van Rossum15e22e11997-12-05 19:03:01 +0000323 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000324
325
326# Expand paths containing shell variable substitutions.
327# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000328# - no expansion within single quotes
Georg Brandl03b90d82007-03-13 22:07:36 +0000329# - '$$' is translated into '$'
330# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000331# - ${varname} is accepted.
Georg Brandl03b90d82007-03-13 22:07:36 +0000332# - $varname is accepted.
333# - %varname% is accepted.
334# - varnames can be made out of letters, digits and the characters '_-'
Ezio Melottic2077b02011-03-16 12:34:31 +0200335# (though is not verified in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000336# XXX With COMMAND.COM you can use any characters in a variable name,
337# XXX except '^|<>='.
338
Tim Peters2344fae2001-01-15 00:50:52 +0000339def expandvars(path):
Georg Brandl03b90d82007-03-13 22:07:36 +0000340 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000341
342 Unknown variables are left unchanged."""
Georg Brandl03b90d82007-03-13 22:07:36 +0000343 if '$' not in path and '%' not in path:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000344 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000345 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000346 varchars = string.ascii_letters + string.digits + '_-'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000347 res = ''
348 index = 0
349 pathlen = len(path)
350 while index < pathlen:
351 c = path[index]
352 if c == '\'': # no expansion within single quotes
353 path = path[index + 1:]
354 pathlen = len(path)
355 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000356 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000357 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000358 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000359 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000360 index = pathlen - 1
Georg Brandl03b90d82007-03-13 22:07:36 +0000361 elif c == '%': # variable or '%'
362 if path[index + 1:index + 2] == '%':
363 res = res + c
364 index = index + 1
365 else:
366 path = path[index+1:]
367 pathlen = len(path)
368 try:
369 index = path.index('%')
370 except ValueError:
371 res = res + '%' + path
372 index = pathlen - 1
373 else:
374 var = path[:index]
375 if var in os.environ:
376 res = res + os.environ[var]
377 else:
378 res = res + '%' + var + '%'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000379 elif c == '$': # variable or '$$'
380 if path[index + 1:index + 2] == '$':
381 res = res + c
382 index = index + 1
383 elif path[index + 1:index + 2] == '{':
384 path = path[index+2:]
385 pathlen = len(path)
386 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000387 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000388 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000389 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000390 res = res + os.environ[var]
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000391 else:
392 res = res + '${' + var + '}'
Fred Drakeb4e460a2000-09-28 16:25:20 +0000393 except ValueError:
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000394 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000395 index = pathlen - 1
396 else:
397 var = ''
398 index = index + 1
399 c = path[index:index + 1]
400 while c != '' and c in varchars:
401 var = var + c
402 index = index + 1
403 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000404 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000405 res = res + os.environ[var]
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000406 else:
407 res = res + '$' + var
Guido van Rossum15e22e11997-12-05 19:03:01 +0000408 if c != '':
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000409 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000410 else:
411 res = res + c
412 index = index + 1
413 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000414
415
Tim Peters54a14a32001-08-30 22:05:26 +0000416# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
Guido van Rossum3df7b5a1996-08-26 16:35:26 +0000417# Previously, this function also truncated pathnames to 8+3 format,
418# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000419
420def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000421 """Normalize path, eliminating double slashes, etc."""
Ezio Melottib5689de2010-01-12 03:32:05 +0000422 # Preserve unicode (if path is unicode)
423 backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.')
Georg Brandle2773252010-08-01 19:14:56 +0000424 if path.startswith(('\\\\.\\', '\\\\?\\')):
425 # in the case of paths with these prefixes:
426 # \\.\ -> device names
427 # \\?\ -> literal paths
428 # do not do any normalization, but return the path unchanged
429 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000430 path = path.replace("/", "\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000431 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000432 # We need to be careful here. If the prefix is empty, and the path starts
433 # with a backslash, it could either be an absolute path on the current
434 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
435 # is therefore imperative NOT to collapse multiple backslashes blindly in
436 # that case.
437 # The code below preserves multiple backslashes when there is no drive
438 # letter. This means that the invalid filename \\\a\b is preserved
439 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
440 # is any better behaviour for such edge cases.
441 if prefix == '':
442 # No drive letter - preserve initial backslashes
443 while path[:1] == "\\":
Ezio Melottib5689de2010-01-12 03:32:05 +0000444 prefix = prefix + backslash
Brett Cannonbdc36272004-07-10 20:42:22 +0000445 path = path[1:]
446 else:
447 # We have a drive letter - collapse initial backslashes
448 if path.startswith("\\"):
Ezio Melottib5689de2010-01-12 03:32:05 +0000449 prefix = prefix + backslash
Brett Cannonbdc36272004-07-10 20:42:22 +0000450 path = path.lstrip("\\")
Fred Drakeb4e460a2000-09-28 16:25:20 +0000451 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000452 i = 0
453 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000454 if comps[i] in ('.', ''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000455 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000456 elif comps[i] == '..':
457 if i > 0 and comps[i-1] != '..':
458 del comps[i-1:i+1]
459 i -= 1
460 elif i == 0 and prefix.endswith("\\"):
461 del comps[i]
462 else:
463 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000464 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000465 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000466 # If the path is now empty, substitute '.'
467 if not prefix and not comps:
Ezio Melottib5689de2010-01-12 03:32:05 +0000468 comps.append(dot)
469 return prefix + backslash.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000470
471
472# Return an absolute path.
Tim Peters21fbd572006-04-21 21:18:10 +0000473try:
474 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000475
Tim Peters21fbd572006-04-21 21:18:10 +0000476except ImportError: # not running on Windows - mock up something sensible
477 def abspath(path):
478 """Return the absolute version of a path."""
479 if not isabs(path):
Ezio Melotti4cc80ca2010-02-20 08:09:39 +0000480 if isinstance(path, unicode):
481 cwd = os.getcwdu()
482 else:
483 cwd = os.getcwd()
484 path = join(cwd, path)
Tim Peters21fbd572006-04-21 21:18:10 +0000485 return normpath(path)
486
487else: # use native Windows method on Windows
488 def abspath(path):
489 """Return the absolute version of a path."""
490
491 if path: # Empty path must return current working directory.
492 try:
493 path = _getfullpathname(path)
494 except WindowsError:
495 pass # Bad path - return unchanged.
Ezio Melotti4cc80ca2010-02-20 08:09:39 +0000496 elif isinstance(path, unicode):
497 path = os.getcwdu()
Tim Peters21fbd572006-04-21 21:18:10 +0000498 else:
499 path = os.getcwd()
500 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000501
502# realpath is a no-op on systems without islink support
503realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000504# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000505supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
506 sys.getwindowsversion()[3] >= 2)
Collin Winter6f187742007-03-16 22:16:08 +0000507
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000508def _abspath_split(path):
509 abs = abspath(normpath(path))
510 prefix, rest = splitunc(abs)
511 is_unc = bool(prefix)
512 if not is_unc:
513 prefix, rest = splitdrive(abs)
514 return is_unc, prefix, [x for x in rest.split(sep) if x]
515
Collin Winter6f187742007-03-16 22:16:08 +0000516def relpath(path, start=curdir):
517 """Return a relative version of a path"""
518
519 if not path:
520 raise ValueError("no path specified")
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000521
522 start_is_unc, start_prefix, start_list = _abspath_split(start)
523 path_is_unc, path_prefix, path_list = _abspath_split(path)
524
525 if path_is_unc ^ start_is_unc:
526 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
527 % (path, start))
528 if path_prefix.lower() != start_prefix.lower():
529 if path_is_unc:
530 raise ValueError("path is on UNC root %s, start on UNC root %s"
531 % (path_prefix, start_prefix))
Collin Winter6f187742007-03-16 22:16:08 +0000532 else:
533 raise ValueError("path is on drive %s, start on drive %s"
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000534 % (path_prefix, start_prefix))
Collin Winter6f187742007-03-16 22:16:08 +0000535 # Work out how much of the filepath is shared by start and path.
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000536 i = 0
537 for e1, e2 in zip(start_list, path_list):
538 if e1.lower() != e2.lower():
Collin Winter6f187742007-03-16 22:16:08 +0000539 break
Collin Winter6f187742007-03-16 22:16:08 +0000540 i += 1
541
542 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Georg Brandl183a0842008-01-06 14:27:15 +0000543 if not rel_list:
544 return curdir
Collin Winter6f187742007-03-16 22:16:08 +0000545 return join(*rel_list)
Brian Curtincaea7e82011-06-08 19:29:53 -0500546
547try:
548 # The genericpath.isdir implementation uses os.stat and checks the mode
549 # attribute to tell whether or not the path is a directory.
550 # This is overkill on Windows - just pass the path to GetFileAttributes
551 # and check the attribute from there.
Brian Curtin5446f082011-06-09 10:00:42 -0500552 from nt import _isdir as isdir
Brian Curtincaea7e82011-06-08 19:29:53 -0500553except ImportError:
Brian Curtin5446f082011-06-09 10:00:42 -0500554 # Use genericpath.isdir as imported above.
555 pass