blob: 9425fd586ef82ebc824b0cf66b78cd2a04235d61 [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",
Benjamin Petersond71ca412008-05-08 23:44:58 +000017 "ismount", "expanduser","expandvars","normpath","abspath",
Georg Brandlf0de6a12005-08-22 18:02:59 +000018 "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
Guido van Rossum555915a1994-02-24 11:32:59 +0000229# Expand paths beginning with '~' or '~user'.
230# '~' means $HOME; '~user' means that user's home directory.
231# If the path doesn't begin with '~', or if the user or $HOME is unknown,
232# the path is returned unchanged (leaving error reporting to whatever
233# function is called with the expanded path as argument).
234# See also module 'glob' for expansion of *, ? and [...] in pathnames.
235# (A function should also be defined to do full *sh-style environment
236# variable expansion.)
237
238def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000239 """Expand ~ and ~user constructs.
240
241 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000242 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000243 return path
244 i, n = 1, len(path)
245 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000246 i = i + 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000247
248 if 'HOME' in os.environ:
249 userhome = os.environ['HOME']
250 elif 'USERPROFILE' in os.environ:
251 userhome = os.environ['USERPROFILE']
252 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000253 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000254 else:
255 try:
256 drive = os.environ['HOMEDRIVE']
257 except KeyError:
258 drive = ''
259 userhome = join(drive, os.environ['HOMEPATH'])
260
261 if i != 1: #~user
262 userhome = join(dirname(userhome), path[1:i])
263
Guido van Rossum15e22e11997-12-05 19:03:01 +0000264 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000265
266
267# Expand paths containing shell variable substitutions.
268# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000269# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000270# - '$$' is translated into '$'
271# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000272# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000273# - $varname is accepted.
274# - %varname% is accepted.
275# - varnames can be made out of letters, digits and the characters '_-'
276# (though is not verifed in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000277# XXX With COMMAND.COM you can use any characters in a variable name,
278# XXX except '^|<>='.
279
Tim Peters2344fae2001-01-15 00:50:52 +0000280def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000281 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000282
283 Unknown variables are left unchanged."""
Guido van Rossumd8faa362007-04-27 19:54:29 +0000284 if '$' not in path and '%' not in path:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000285 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000286 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000287 varchars = string.ascii_letters + string.digits + '_-'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000288 res = ''
289 index = 0
290 pathlen = len(path)
291 while index < pathlen:
292 c = path[index]
293 if c == '\'': # no expansion within single quotes
294 path = path[index + 1:]
295 pathlen = len(path)
296 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000297 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000298 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000299 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000300 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000301 index = pathlen - 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000302 elif c == '%': # variable or '%'
303 if path[index + 1:index + 2] == '%':
304 res = res + c
305 index = index + 1
306 else:
307 path = path[index+1:]
308 pathlen = len(path)
309 try:
310 index = path.index('%')
311 except ValueError:
312 res = res + '%' + path
313 index = pathlen - 1
314 else:
315 var = path[:index]
316 if var in os.environ:
317 res = res + os.environ[var]
318 else:
319 res = res + '%' + var + '%'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000320 elif c == '$': # variable or '$$'
321 if path[index + 1:index + 2] == '$':
322 res = res + c
323 index = index + 1
324 elif path[index + 1:index + 2] == '{':
325 path = path[index+2:]
326 pathlen = len(path)
327 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000328 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000329 var = path[:index]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000330 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000331 res = res + os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000332 else:
333 res = res + '${' + var + '}'
Fred Drakeb4e460a2000-09-28 16:25:20 +0000334 except ValueError:
Thomas Woutersb2137042007-02-01 18:02:27 +0000335 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000336 index = pathlen - 1
337 else:
338 var = ''
339 index = index + 1
340 c = path[index:index + 1]
341 while c != '' and c in varchars:
342 var = var + c
343 index = index + 1
344 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000345 if var in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000346 res = res + os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000347 else:
348 res = res + '$' + var
Guido van Rossum15e22e11997-12-05 19:03:01 +0000349 if c != '':
Thomas Woutersb2137042007-02-01 18:02:27 +0000350 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000351 else:
352 res = res + c
353 index = index + 1
354 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000355
356
Tim Peters54a14a32001-08-30 22:05:26 +0000357# 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 +0000358# Previously, this function also truncated pathnames to 8+3 format,
359# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000360
361def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000362 """Normalize path, eliminating double slashes, etc."""
Fred Drakeb4e460a2000-09-28 16:25:20 +0000363 path = path.replace("/", "\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000364 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000365 # We need to be careful here. If the prefix is empty, and the path starts
366 # with a backslash, it could either be an absolute path on the current
367 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
368 # is therefore imperative NOT to collapse multiple backslashes blindly in
369 # that case.
370 # The code below preserves multiple backslashes when there is no drive
371 # letter. This means that the invalid filename \\\a\b is preserved
372 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
373 # is any better behaviour for such edge cases.
374 if prefix == '':
375 # No drive letter - preserve initial backslashes
376 while path[:1] == "\\":
377 prefix = prefix + "\\"
378 path = path[1:]
379 else:
380 # We have a drive letter - collapse initial backslashes
381 if path.startswith("\\"):
382 prefix = prefix + "\\"
383 path = path.lstrip("\\")
Fred Drakeb4e460a2000-09-28 16:25:20 +0000384 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000385 i = 0
386 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000387 if comps[i] in ('.', ''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000388 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000389 elif comps[i] == '..':
390 if i > 0 and comps[i-1] != '..':
391 del comps[i-1:i+1]
392 i -= 1
393 elif i == 0 and prefix.endswith("\\"):
394 del comps[i]
395 else:
396 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000397 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000398 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000399 # If the path is now empty, substitute '.'
400 if not prefix and not comps:
401 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000402 return prefix + "\\".join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000403
404
405# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000406try:
407 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000408
Thomas Wouters477c8d52006-05-27 19:21:47 +0000409except ImportError: # not running on Windows - mock up something sensible
410 def abspath(path):
411 """Return the absolute version of a path."""
412 if not isabs(path):
413 path = join(os.getcwd(), path)
414 return normpath(path)
415
416else: # use native Windows method on Windows
417 def abspath(path):
418 """Return the absolute version of a path."""
419
420 if path: # Empty path must return current working directory.
421 try:
422 path = _getfullpathname(path)
423 except WindowsError:
424 pass # Bad path - return unchanged.
425 else:
426 path = os.getcwd()
427 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000428
429# realpath is a no-op on systems without islink support
430realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000431# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000432supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
433 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000434
435def relpath(path, start=curdir):
436 """Return a relative version of a path"""
437
438 if not path:
439 raise ValueError("no path specified")
440 start_list = abspath(start).split(sep)
441 path_list = abspath(path).split(sep)
442 if start_list[0].lower() != path_list[0].lower():
443 unc_path, rest = splitunc(path)
444 unc_start, rest = splitunc(start)
445 if bool(unc_path) ^ bool(unc_start):
446 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
447 % (path, start))
448 else:
449 raise ValueError("path is on drive %s, start on drive %s"
450 % (path_list[0], start_list[0]))
451 # Work out how much of the filepath is shared by start and path.
452 for i in range(min(len(start_list), len(path_list))):
453 if start_list[i].lower() != path_list[i].lower():
454 break
455 else:
456 i += 1
457
458 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Christian Heimesfaf2f632008-01-06 16:59:19 +0000459 if not rel_list:
460 return curdir
Guido van Rossumd8faa362007-04-27 19:54:29 +0000461 return join(*rel_list)