blob: 59f1402288b893fa831a48bc477a15637faed177 [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 Heimes05e8be12008-02-23 18:30:17 +000010import stat
Guido van Rossumd8faa362007-04-27 19:54:29 +000011import genericpath
Thomas Wouters89f507f2006-12-13 04:49:30 +000012from genericpath import *
Skip Montanaro4d5d5bf2000-07-13 01:01:03 +000013
Skip Montanaro269b83b2001-02-06 01:07:02 +000014__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
15 "basename","dirname","commonprefix","getsize","getmtime",
Georg Brandlf0de6a12005-08-22 18:02:59 +000016 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
17 "ismount","walk","expanduser","expandvars","normpath","abspath",
18 "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
Guido van Rossumd8faa362007-04-27 19:54:29 +000019 "extsep","devnull","realpath","supports_unicode_filenames","relpath"]
Guido van Rossum555915a1994-02-24 11:32:59 +000020
Skip Montanaro117910d2003-02-14 19:35:31 +000021# strings representing various path-related bits and pieces
22curdir = '.'
23pardir = '..'
24extsep = '.'
25sep = '\\'
26pathsep = ';'
Skip Montanaro9ddac3e2003-03-28 22:23:24 +000027altsep = '/'
Andrew MacIntyre437966c2003-02-17 09:17:50 +000028defpath = '.;C:\\bin'
Skip Montanaro117910d2003-02-14 19:35:31 +000029if 'ce' in sys.builtin_module_names:
30 defpath = '\\Windows'
31elif 'os2' in sys.builtin_module_names:
Andrew MacIntyre437966c2003-02-17 09:17:50 +000032 # OS/2 w/ VACPP
Skip Montanaro117910d2003-02-14 19:35:31 +000033 altsep = '/'
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000034devnull = 'nul'
Skip Montanaro117910d2003-02-14 19:35:31 +000035
Guido van Rossume2ad88c1997-08-12 14:46:58 +000036# Normalize the case of a pathname and map slashes to backslashes.
37# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000038# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000039
Guido van Rossum555915a1994-02-24 11:32:59 +000040def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000041 """Normalize case of pathname.
42
Guido van Rossum534972b1999-02-03 17:20:50 +000043 Makes all characters lowercase and all slashes into backslashes."""
Fred Drakeb4e460a2000-09-28 16:25:20 +000044 return s.replace("/", "\\").lower()
Guido van Rossum555915a1994-02-24 11:32:59 +000045
Guido van Rossum77e1db31997-06-02 23:11:57 +000046
Fred Drakeef0b5dd2000-02-17 17:30:40 +000047# Return whether a path is absolute.
Guido van Rossum555915a1994-02-24 11:32:59 +000048# Trivial in Posix, harder on the Mac or MS-DOS.
49# For DOS it is absolute if it starts with a slash or backslash (current
Guido van Rossum534972b1999-02-03 17:20:50 +000050# volume), or if a pathname after the volume letter and colon / UNC resource
51# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000052
53def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000054 """Test whether a path is absolute"""
55 s = splitdrive(s)[1]
56 return s != '' and s[:1] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +000057
58
Guido van Rossum77e1db31997-06-02 23:11:57 +000059# Join two (or more) paths.
60
Barry Warsaw384d2491997-02-18 21:53:25 +000061def join(a, *p):
Guido van Rossum04110fb2007-08-24 16:32:05 +000062 """Join two or more pathname components, inserting "\\" as needed.
63 If any component is an absolute path, all previous path components
64 will be discarded."""
Guido van Rossum15e22e11997-12-05 19:03:01 +000065 path = a
66 for b in p:
Tim Peters33dc0a12001-07-27 08:09:54 +000067 b_wins = 0 # set to 1 iff b makes path irrelevant
68 if path == "":
69 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000070
Tim Peters33dc0a12001-07-27 08:09:54 +000071 elif isabs(b):
72 # This probably wipes out path so far. However, it's more
73 # complicated if path begins with a drive letter:
74 # 1. join('c:', '/a') == 'c:/a'
75 # 2. join('c:/', '/a') == 'c:/a'
76 # But
77 # 3. join('c:/a', '/b') == '/b'
78 # 4. join('c:', 'd:/') = 'd:/'
79 # 5. join('c:/', 'd:/') = 'd:/'
80 if path[1:2] != ":" or b[1:2] == ":":
81 # Path doesn't start with a drive letter, or cases 4 and 5.
82 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000083
Tim Peters33dc0a12001-07-27 08:09:54 +000084 # Else path has a drive letter, and b doesn't but is absolute.
85 elif len(path) > 3 or (len(path) == 3 and
86 path[-1] not in "/\\"):
87 # case 3
88 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000089
Tim Peters33dc0a12001-07-27 08:09:54 +000090 if b_wins:
91 path = b
92 else:
93 # Join, and ensure there's a separator.
94 assert len(path) > 0
95 if path[-1] in "/\\":
96 if b and b[0] in "/\\":
97 path += b[1:]
98 else:
99 path += b
100 elif path[-1] == ":":
101 path += b
102 elif b:
103 if b[0] in "/\\":
104 path += b
105 else:
106 path += "\\" + b
Tim Peters6a3e5f12001-11-05 21:25:02 +0000107 else:
108 # path is not empty and does not end with a backslash,
109 # but b is empty; since, e.g., split('a/') produces
110 # ('a', ''), it's best if join() adds a backslash in
111 # this case.
112 path += '\\'
Tim Peters1bdd0f22001-07-19 17:18:18 +0000113
Guido van Rossum15e22e11997-12-05 19:03:01 +0000114 return path
Guido van Rossum555915a1994-02-24 11:32:59 +0000115
116
117# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000118# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000119# It is always true that drivespec + pathspec == p
120def splitdrive(p):
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000121 """Split a pathname into drive and path specifiers. Returns a 2-tuple
122"(drive,path)"; either part may be empty"""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000123 if p[1:2] == ':':
124 return p[0:2], p[2:]
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000125 return '', p
126
127
128# Parse UNC paths
129def splitunc(p):
130 """Split a pathname into UNC mount point and relative path specifiers.
131
132 Return a 2-tuple (unc, rest); either part may be empty.
133 If unc is not empty, it has the form '//host/mount' (or similar
134 using backslashes). unc+rest is always the input path.
135 Paths containing drive letters never have an UNC part.
136 """
137 if p[1:2] == ':':
138 return '', p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000139 firstTwo = p[0:2]
140 if firstTwo == '//' or firstTwo == '\\\\':
141 # is a UNC path:
142 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
143 # \\machine\mountpoint\directories...
144 # directory ^^^^^^^^^^^^^^^
145 normp = normcase(p)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000146 index = normp.find('\\', 2)
Guido van Rossum534972b1999-02-03 17:20:50 +0000147 if index == -1:
148 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
149 return ("", p)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000150 index = normp.find('\\', index + 1)
Guido van Rossum534972b1999-02-03 17:20:50 +0000151 if index == -1:
152 index = len(p)
153 return p[:index], p[index:]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000154 return '', p
Guido van Rossum555915a1994-02-24 11:32:59 +0000155
156
157# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000158# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000159# join(head, tail) == p holds.
160# The resulting head won't end in '/' unless it is the root.
161
162def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000163 """Split a pathname.
164
165 Return tuple (head, tail) where tail is everything after the final slash.
166 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000167
Guido van Rossum15e22e11997-12-05 19:03:01 +0000168 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000169 # set i to index beyond p's last slash
170 i = len(p)
171 while i and p[i-1] not in '/\\':
172 i = i - 1
173 head, tail = p[:i], p[i:] # now tail has no slashes
174 # remove trailing slashes from head, unless it's all slashes
175 head2 = head
176 while head2 and head2[-1] in '/\\':
177 head2 = head2[:-1]
178 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000179 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000180
181
182# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000183# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000184# pathname component; the root is everything before that.
185# It is always true that root + ext == p.
186
187def splitext(p):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000188 return genericpath._splitext(p, sep, altsep, extsep)
189splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000190
191
192# Return the tail (basename) part of a path.
193
194def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000195 """Returns the final component of a pathname"""
196 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000197
198
199# Return the head (dirname) part of a path.
200
201def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000202 """Returns the directory component of a pathname"""
203 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000204
Guido van Rossum555915a1994-02-24 11:32:59 +0000205# Is a path a symbolic link?
206# This will always return false on systems where posix.lstat doesn't exist.
207
208def islink(path):
Thomas Wouters89f507f2006-12-13 04:49:30 +0000209 """Test for symbolic link.
210 On WindowsNT/95 and OS/2 always returns false
211 """
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000212 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000213
Thomas Wouters89f507f2006-12-13 04:49:30 +0000214# alias exists to lexists
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000215lexists = exists
216
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000217# Is a path a mount point? Either a root (with or without drive letter)
218# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000219
220def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000221 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000222 unc, rest = splitunc(path)
223 if unc:
224 return rest in ("", "/", "\\")
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000225 p = splitdrive(path)[1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000226 return len(p) == 1 and p[0] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +0000227
228
229# Directory tree walk.
230# For each directory under top (including top itself, but excluding
231# '.' and '..'), func(arg, dirname, filenames) is called, where
232# dirname is the name of the directory and filenames is the list
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +0000233# of files (and subdirectories etc.) in the directory.
Guido van Rossum555915a1994-02-24 11:32:59 +0000234# The func may modify the filenames list, to implement a filter,
235# or to impose a different order of visiting.
236
237def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000238 """Directory tree walk with callback function.
Guido van Rossum534972b1999-02-03 17:20:50 +0000239
Tim Peterscf5e6a42001-10-10 04:16:20 +0000240 For each directory in the directory tree rooted at top (including top
241 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
242 dirname is the name of the directory, and fnames a list of the names of
243 the files and subdirectories in dirname (excluding '.' and '..'). func
244 may modify the fnames list in-place (e.g. via del or slice assignment),
245 and walk will only recurse into the subdirectories whose names remain in
246 fnames; this can be used to implement a filter, or to impose a specific
247 order of visiting. No semantics are defined for, or required of, arg,
248 beyond that arg is always passed to func. It can be used, e.g., to pass
249 a filename pattern, or a mutable object designed to accumulate
250 statistics. Passing None for arg is common."""
251
Guido van Rossum15e22e11997-12-05 19:03:01 +0000252 try:
253 names = os.listdir(top)
254 except os.error:
255 return
256 func(arg, top, names)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000257 for name in names:
Christian Heimesfaf2f632008-01-06 16:59:19 +0000258 name = join(top, name)
259 if isdir(name):
260 walk(name, func, arg)
Guido van Rossum555915a1994-02-24 11:32:59 +0000261
262
263# Expand paths beginning with '~' or '~user'.
264# '~' means $HOME; '~user' means that user's home directory.
265# If the path doesn't begin with '~', or if the user or $HOME is unknown,
266# the path is returned unchanged (leaving error reporting to whatever
267# function is called with the expanded path as argument).
268# See also module 'glob' for expansion of *, ? and [...] in pathnames.
269# (A function should also be defined to do full *sh-style environment
270# variable expansion.)
271
272def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000273 """Expand ~ and ~user constructs.
274
275 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000276 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000277 return path
278 i, n = 1, len(path)
279 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000280 i = i + 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000281
282 if 'HOME' in os.environ:
283 userhome = os.environ['HOME']
284 elif 'USERPROFILE' in os.environ:
285 userhome = os.environ['USERPROFILE']
286 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000287 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000288 else:
289 try:
290 drive = os.environ['HOMEDRIVE']
291 except KeyError:
292 drive = ''
293 userhome = join(drive, os.environ['HOMEPATH'])
294
295 if i != 1: #~user
296 userhome = join(dirname(userhome), path[1:i])
297
Guido van Rossum15e22e11997-12-05 19:03:01 +0000298 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000299
300
301# Expand paths containing shell variable substitutions.
302# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000303# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000304# - '$$' is translated into '$'
305# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000306# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000307# - $varname is accepted.
308# - %varname% is accepted.
309# - varnames can be made out of letters, digits and the characters '_-'
310# (though is not verifed in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000311# XXX With COMMAND.COM you can use any characters in a variable name,
312# XXX except '^|<>='.
313
Tim Peters2344fae2001-01-15 00:50:52 +0000314def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000315 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000316
317 Unknown variables are left unchanged."""
Guido van Rossumd8faa362007-04-27 19:54:29 +0000318 if '$' not in path and '%' not in path:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000319 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000320 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000321 varchars = string.ascii_letters + string.digits + '_-'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000322 res = ''
323 index = 0
324 pathlen = len(path)
325 while index < pathlen:
326 c = path[index]
327 if c == '\'': # no expansion within single quotes
328 path = path[index + 1:]
329 pathlen = len(path)
330 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000331 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000332 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000333 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000334 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000335 index = pathlen - 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000336 elif c == '%': # variable or '%'
337 if path[index + 1:index + 2] == '%':
338 res = res + c
339 index = index + 1
340 else:
341 path = path[index+1:]
342 pathlen = len(path)
343 try:
344 index = path.index('%')
345 except ValueError:
346 res = res + '%' + path
347 index = pathlen - 1
348 else:
349 var = path[:index]
350 if var in os.environ:
351 res = res + os.environ[var]
352 else:
353 res = res + '%' + var + '%'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000354 elif c == '$': # variable or '$$'
355 if path[index + 1:index + 2] == '$':
356 res = res + c
357 index = index + 1
358 elif path[index + 1:index + 2] == '{':
359 path = path[index+2:]
360 pathlen = len(path)
361 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000362 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000363 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000364 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000365 res = res + os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000366 else:
367 res = res + '${' + var + '}'
Fred Drakeb4e460a2000-09-28 16:25:20 +0000368 except ValueError:
Thomas Woutersb2137042007-02-01 18:02:27 +0000369 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000370 index = pathlen - 1
371 else:
372 var = ''
373 index = index + 1
374 c = path[index:index + 1]
375 while c != '' and c in varchars:
376 var = var + c
377 index = index + 1
378 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000379 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000380 res = res + os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000381 else:
382 res = res + '$' + var
Guido van Rossum15e22e11997-12-05 19:03:01 +0000383 if c != '':
Thomas Woutersb2137042007-02-01 18:02:27 +0000384 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000385 else:
386 res = res + c
387 index = index + 1
388 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000389
390
Tim Peters54a14a32001-08-30 22:05:26 +0000391# 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 +0000392# Previously, this function also truncated pathnames to 8+3 format,
393# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000394
395def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000396 """Normalize path, eliminating double slashes, etc."""
Fred Drakeb4e460a2000-09-28 16:25:20 +0000397 path = path.replace("/", "\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000398 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000399 # We need to be careful here. If the prefix is empty, and the path starts
400 # with a backslash, it could either be an absolute path on the current
401 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
402 # is therefore imperative NOT to collapse multiple backslashes blindly in
403 # that case.
404 # The code below preserves multiple backslashes when there is no drive
405 # letter. This means that the invalid filename \\\a\b is preserved
406 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
407 # is any better behaviour for such edge cases.
408 if prefix == '':
409 # No drive letter - preserve initial backslashes
410 while path[:1] == "\\":
411 prefix = prefix + "\\"
412 path = path[1:]
413 else:
414 # We have a drive letter - collapse initial backslashes
415 if path.startswith("\\"):
416 prefix = prefix + "\\"
417 path = path.lstrip("\\")
Fred Drakeb4e460a2000-09-28 16:25:20 +0000418 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000419 i = 0
420 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000421 if comps[i] in ('.', ''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000422 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000423 elif comps[i] == '..':
424 if i > 0 and comps[i-1] != '..':
425 del comps[i-1:i+1]
426 i -= 1
427 elif i == 0 and prefix.endswith("\\"):
428 del comps[i]
429 else:
430 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000431 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000432 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000433 # If the path is now empty, substitute '.'
434 if not prefix and not comps:
435 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000436 return prefix + "\\".join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000437
438
439# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000440try:
441 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000442
Thomas Wouters477c8d52006-05-27 19:21:47 +0000443except ImportError: # not running on Windows - mock up something sensible
444 def abspath(path):
445 """Return the absolute version of a path."""
446 if not isabs(path):
447 path = join(os.getcwd(), path)
448 return normpath(path)
449
450else: # use native Windows method on Windows
451 def abspath(path):
452 """Return the absolute version of a path."""
453
454 if path: # Empty path must return current working directory.
455 try:
456 path = _getfullpathname(path)
457 except WindowsError:
458 pass # Bad path - return unchanged.
459 else:
460 path = os.getcwd()
461 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000462
463# realpath is a no-op on systems without islink support
464realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000465# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000466supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
467 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000468
469def relpath(path, start=curdir):
470 """Return a relative version of a path"""
471
472 if not path:
473 raise ValueError("no path specified")
474 start_list = abspath(start).split(sep)
475 path_list = abspath(path).split(sep)
476 if start_list[0].lower() != path_list[0].lower():
477 unc_path, rest = splitunc(path)
478 unc_start, rest = splitunc(start)
479 if bool(unc_path) ^ bool(unc_start):
480 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
481 % (path, start))
482 else:
483 raise ValueError("path is on drive %s, start on drive %s"
484 % (path_list[0], start_list[0]))
485 # Work out how much of the filepath is shared by start and path.
486 for i in range(min(len(start_list), len(path_list))):
487 if start_list[i].lower() != path_list[i].lower():
488 break
489 else:
490 i += 1
491
492 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Christian Heimesfaf2f632008-01-06 16:59:19 +0000493 if not rel_list:
494 return curdir
Guido van Rossumd8faa362007-04-27 19:54:29 +0000495 return join(*rel_list)