blob: 714f2054161ed2b731be7a57f3cb502d56ee1d34 [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 """
139 if p[1:2] == ':':
140 return '', p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000141 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)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000148 index = normp.find('\\', 2)
Guido van Rossum534972b1999-02-03 17:20:50 +0000149 if index == -1:
150 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
151 return ("", p)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000152 index = normp.find('\\', index + 1)
Guido van Rossum534972b1999-02-03 17:20:50 +0000153 if index == -1:
154 index = len(p)
155 return p[:index], p[index:]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000156 return '', p
Guido van Rossum555915a1994-02-24 11:32:59 +0000157
158
159# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000160# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000161# join(head, tail) == p holds.
162# The resulting head won't end in '/' unless it is the root.
163
164def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000165 """Split a pathname.
166
167 Return tuple (head, tail) where tail is everything after the final slash.
168 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000169
Guido van Rossum15e22e11997-12-05 19:03:01 +0000170 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000171 # set i to index beyond p's last slash
172 i = len(p)
173 while i and p[i-1] not in '/\\':
174 i = i - 1
175 head, tail = p[:i], p[i:] # now tail has no slashes
176 # remove trailing slashes from head, unless it's all slashes
177 head2 = head
178 while head2 and head2[-1] in '/\\':
179 head2 = head2[:-1]
180 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000181 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000182
183
184# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000185# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000186# pathname component; the root is everything before that.
187# It is always true that root + ext == p.
188
189def splitext(p):
Martin v. Löwis05c075d2007-03-07 11:04:33 +0000190 return genericpath._splitext(p, sep, altsep, extsep)
191splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000192
193
194# Return the tail (basename) part of a path.
195
196def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000197 """Returns the final component of a pathname"""
198 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000199
200
201# Return the head (dirname) part of a path.
202
203def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000204 """Returns the directory component of a pathname"""
205 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000206
Guido van Rossum555915a1994-02-24 11:32:59 +0000207# Is a path a symbolic link?
208# This will always return false on systems where posix.lstat doesn't exist.
209
210def islink(path):
Jack Diederich7b604642006-08-26 18:42:06 +0000211 """Test for symbolic link.
212 On WindowsNT/95 and OS/2 always returns false
213 """
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000214 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000215
Jack Diederich7b604642006-08-26 18:42:06 +0000216# alias exists to lexists
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000217lexists = exists
218
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000219# Is a path a mount point? Either a root (with or without drive letter)
220# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000221
222def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000223 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000224 unc, rest = splitunc(path)
225 if unc:
226 return rest in ("", "/", "\\")
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000227 p = splitdrive(path)[1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000228 return len(p) == 1 and p[0] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +0000229
230
231# Directory tree walk.
232# For each directory under top (including top itself, but excluding
233# '.' and '..'), func(arg, dirname, filenames) is called, where
234# dirname is the name of the directory and filenames is the list
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +0000235# of files (and subdirectories etc.) in the directory.
Guido van Rossum555915a1994-02-24 11:32:59 +0000236# The func may modify the filenames list, to implement a filter,
237# or to impose a different order of visiting.
238
239def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000240 """Directory tree walk with callback function.
Guido van Rossum534972b1999-02-03 17:20:50 +0000241
Tim Peterscf5e6a42001-10-10 04:16:20 +0000242 For each directory in the directory tree rooted at top (including top
243 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
244 dirname is the name of the directory, and fnames a list of the names of
245 the files and subdirectories in dirname (excluding '.' and '..'). func
246 may modify the fnames list in-place (e.g. via del or slice assignment),
247 and walk will only recurse into the subdirectories whose names remain in
248 fnames; this can be used to implement a filter, or to impose a specific
249 order of visiting. No semantics are defined for, or required of, arg,
250 beyond that arg is always passed to func. It can be used, e.g., to pass
251 a filename pattern, or a mutable object designed to accumulate
252 statistics. Passing None for arg is common."""
Benjamin Peterson0893a0a2008-05-09 00:27:01 +0000253 warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000254 try:
255 names = os.listdir(top)
256 except os.error:
257 return
258 func(arg, top, names)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000259 for name in names:
Georg Brandle2a902c2008-01-06 14:17:36 +0000260 name = join(top, name)
261 if isdir(name):
262 walk(name, func, arg)
Guido van Rossum555915a1994-02-24 11:32:59 +0000263
264
265# Expand paths beginning with '~' or '~user'.
266# '~' means $HOME; '~user' means that user's home directory.
267# If the path doesn't begin with '~', or if the user or $HOME is unknown,
268# the path is returned unchanged (leaving error reporting to whatever
269# function is called with the expanded path as argument).
270# See also module 'glob' for expansion of *, ? and [...] in pathnames.
271# (A function should also be defined to do full *sh-style environment
272# variable expansion.)
273
274def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000275 """Expand ~ and ~user constructs.
276
277 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000278 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000279 return path
280 i, n = 1, len(path)
281 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000282 i = i + 1
Georg Brandl03b90d82007-03-13 22:07:36 +0000283
284 if 'HOME' in os.environ:
285 userhome = os.environ['HOME']
286 elif 'USERPROFILE' in os.environ:
287 userhome = os.environ['USERPROFILE']
288 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000289 return path
Georg Brandl03b90d82007-03-13 22:07:36 +0000290 else:
291 try:
292 drive = os.environ['HOMEDRIVE']
293 except KeyError:
294 drive = ''
295 userhome = join(drive, os.environ['HOMEPATH'])
296
297 if i != 1: #~user
298 userhome = join(dirname(userhome), path[1:i])
299
Guido van Rossum15e22e11997-12-05 19:03:01 +0000300 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000301
302
303# Expand paths containing shell variable substitutions.
304# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000305# - no expansion within single quotes
Georg Brandl03b90d82007-03-13 22:07:36 +0000306# - '$$' is translated into '$'
307# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000308# - ${varname} is accepted.
Georg Brandl03b90d82007-03-13 22:07:36 +0000309# - $varname is accepted.
310# - %varname% is accepted.
311# - varnames can be made out of letters, digits and the characters '_-'
312# (though is not verifed in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000313# XXX With COMMAND.COM you can use any characters in a variable name,
314# XXX except '^|<>='.
315
Tim Peters2344fae2001-01-15 00:50:52 +0000316def expandvars(path):
Georg Brandl03b90d82007-03-13 22:07:36 +0000317 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000318
319 Unknown variables are left unchanged."""
Georg Brandl03b90d82007-03-13 22:07:36 +0000320 if '$' not in path and '%' not in path:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000321 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000322 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000323 varchars = string.ascii_letters + string.digits + '_-'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000324 res = ''
325 index = 0
326 pathlen = len(path)
327 while index < pathlen:
328 c = path[index]
329 if c == '\'': # no expansion within single quotes
330 path = path[index + 1:]
331 pathlen = len(path)
332 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000333 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000334 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000335 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000336 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000337 index = pathlen - 1
Georg Brandl03b90d82007-03-13 22:07:36 +0000338 elif c == '%': # variable or '%'
339 if path[index + 1:index + 2] == '%':
340 res = res + c
341 index = index + 1
342 else:
343 path = path[index+1:]
344 pathlen = len(path)
345 try:
346 index = path.index('%')
347 except ValueError:
348 res = res + '%' + path
349 index = pathlen - 1
350 else:
351 var = path[:index]
352 if var in os.environ:
353 res = res + os.environ[var]
354 else:
355 res = res + '%' + var + '%'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000356 elif c == '$': # variable or '$$'
357 if path[index + 1:index + 2] == '$':
358 res = res + c
359 index = index + 1
360 elif path[index + 1:index + 2] == '{':
361 path = path[index+2:]
362 pathlen = len(path)
363 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000364 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000365 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000366 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000367 res = res + os.environ[var]
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000368 else:
369 res = res + '${' + var + '}'
Fred Drakeb4e460a2000-09-28 16:25:20 +0000370 except ValueError:
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000371 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000372 index = pathlen - 1
373 else:
374 var = ''
375 index = index + 1
376 c = path[index:index + 1]
377 while c != '' and c in varchars:
378 var = var + c
379 index = index + 1
380 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000381 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000382 res = res + os.environ[var]
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000383 else:
384 res = res + '$' + var
Guido van Rossum15e22e11997-12-05 19:03:01 +0000385 if c != '':
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000386 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000387 else:
388 res = res + c
389 index = index + 1
390 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000391
392
Tim Peters54a14a32001-08-30 22:05:26 +0000393# 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 +0000394# Previously, this function also truncated pathnames to 8+3 format,
395# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000396
397def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000398 """Normalize path, eliminating double slashes, etc."""
Fred Drakeb4e460a2000-09-28 16:25:20 +0000399 path = path.replace("/", "\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000400 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000401 # We need to be careful here. If the prefix is empty, and the path starts
402 # with a backslash, it could either be an absolute path on the current
403 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
404 # is therefore imperative NOT to collapse multiple backslashes blindly in
405 # that case.
406 # The code below preserves multiple backslashes when there is no drive
407 # letter. This means that the invalid filename \\\a\b is preserved
408 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
409 # is any better behaviour for such edge cases.
410 if prefix == '':
411 # No drive letter - preserve initial backslashes
412 while path[:1] == "\\":
413 prefix = prefix + "\\"
414 path = path[1:]
415 else:
416 # We have a drive letter - collapse initial backslashes
417 if path.startswith("\\"):
418 prefix = prefix + "\\"
419 path = path.lstrip("\\")
Fred Drakeb4e460a2000-09-28 16:25:20 +0000420 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000421 i = 0
422 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000423 if comps[i] in ('.', ''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000424 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000425 elif comps[i] == '..':
426 if i > 0 and comps[i-1] != '..':
427 del comps[i-1:i+1]
428 i -= 1
429 elif i == 0 and prefix.endswith("\\"):
430 del comps[i]
431 else:
432 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000433 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000434 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000435 # If the path is now empty, substitute '.'
436 if not prefix and not comps:
437 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000438 return prefix + "\\".join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000439
440
441# Return an absolute path.
Tim Peters21fbd572006-04-21 21:18:10 +0000442try:
443 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000444
Tim Peters21fbd572006-04-21 21:18:10 +0000445except ImportError: # not running on Windows - mock up something sensible
446 def abspath(path):
447 """Return the absolute version of a path."""
448 if not isabs(path):
449 path = join(os.getcwd(), path)
450 return normpath(path)
451
452else: # use native Windows method on Windows
453 def abspath(path):
454 """Return the absolute version of a path."""
455
456 if path: # Empty path must return current working directory.
457 try:
458 path = _getfullpathname(path)
459 except WindowsError:
460 pass # Bad path - return unchanged.
461 else:
462 path = os.getcwd()
463 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000464
465# realpath is a no-op on systems without islink support
466realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000467# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000468supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
469 sys.getwindowsversion()[3] >= 2)
Collin Winter6f187742007-03-16 22:16:08 +0000470
471def relpath(path, start=curdir):
472 """Return a relative version of a path"""
473
474 if not path:
475 raise ValueError("no path specified")
476 start_list = abspath(start).split(sep)
477 path_list = abspath(path).split(sep)
478 if start_list[0].lower() != path_list[0].lower():
479 unc_path, rest = splitunc(path)
480 unc_start, rest = splitunc(start)
481 if bool(unc_path) ^ bool(unc_start):
482 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
483 % (path, start))
484 else:
485 raise ValueError("path is on drive %s, start on drive %s"
486 % (path_list[0], start_list[0]))
487 # Work out how much of the filepath is shared by start and path.
488 for i in range(min(len(start_list), len(path_list))):
489 if start_list[i].lower() != path_list[i].lower():
490 break
491 else:
492 i += 1
493
494 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Georg Brandl183a0842008-01-06 14:27:15 +0000495 if not rel_list:
496 return curdir
Collin Winter6f187742007-03-16 22:16:08 +0000497 return join(*rel_list)