blob: 42469fe07e9fd24fa679549f112987e6d54693e0 [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.
Serhiy Storchaka31f51212014-01-27 23:14:51 +020062def join(path, *paths):
63 """Join two or more pathname components, inserting "\\" as needed."""
64 result_drive, result_path = splitdrive(path)
65 for p in paths:
66 p_drive, p_path = splitdrive(p)
67 if p_path and p_path[0] in '\\/':
68 # Second path is absolute
69 if p_drive or not result_drive:
70 result_drive = p_drive
71 result_path = p_path
72 continue
73 elif p_drive and p_drive != result_drive:
74 if p_drive.lower() != result_drive.lower():
75 # Different drives => ignore the first path entirely
76 result_drive = p_drive
77 result_path = p_path
78 continue
79 # Same drive in different case
80 result_drive = p_drive
81 # Second path is relative to the first
82 if result_path and result_path[-1] not in '\\/':
83 result_path = result_path + '\\'
84 result_path = result_path + p_path
85 return result_drive + result_path
Guido van Rossum555915a1994-02-24 11:32:59 +000086
87
88# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +000089# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +000090# It is always true that drivespec + pathspec == p
91def splitdrive(p):
Guido van Rossumf3c695c1999-04-06 19:32:19 +000092 """Split a pathname into drive and path specifiers. Returns a 2-tuple
93"(drive,path)"; either part may be empty"""
Guido van Rossum15e22e11997-12-05 19:03:01 +000094 if p[1:2] == ':':
95 return p[0:2], p[2:]
Guido van Rossumf3c695c1999-04-06 19:32:19 +000096 return '', p
97
98
99# Parse UNC paths
100def splitunc(p):
101 """Split a pathname into UNC mount point and relative path specifiers.
102
103 Return a 2-tuple (unc, rest); either part may be empty.
104 If unc is not empty, it has the form '//host/mount' (or similar
105 using backslashes). unc+rest is always the input path.
106 Paths containing drive letters never have an UNC part.
107 """
108 if p[1:2] == ':':
109 return '', p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000110 firstTwo = p[0:2]
111 if firstTwo == '//' or firstTwo == '\\\\':
112 # is a UNC path:
113 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
114 # \\machine\mountpoint\directories...
115 # directory ^^^^^^^^^^^^^^^
Serhiy Storchakadd5a46c2013-12-16 15:15:29 +0200116 normp = p.replace('\\', '/')
117 index = normp.find('/', 2)
118 if index <= 2:
119 return '', p
120 index2 = normp.find('/', index + 1)
121 # a UNC path can't have two slashes in a row
122 # (after the initial two)
123 if index2 == index + 1:
124 return '', p
125 if index2 == -1:
126 index2 = len(p)
127 return p[:index2], p[index2:]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000128 return '', p
Guido van Rossum555915a1994-02-24 11:32:59 +0000129
130
131# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000132# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000133# join(head, tail) == p holds.
134# The resulting head won't end in '/' unless it is the root.
135
136def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000137 """Split a pathname.
138
139 Return tuple (head, tail) where tail is everything after the final slash.
140 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000141
Guido van Rossum15e22e11997-12-05 19:03:01 +0000142 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000143 # set i to index beyond p's last slash
144 i = len(p)
145 while i and p[i-1] not in '/\\':
146 i = i - 1
147 head, tail = p[:i], p[i:] # now tail has no slashes
148 # remove trailing slashes from head, unless it's all slashes
149 head2 = head
150 while head2 and head2[-1] in '/\\':
151 head2 = head2[:-1]
152 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000153 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000154
155
156# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000157# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000158# pathname component; the root is everything before that.
159# It is always true that root + ext == p.
160
161def splitext(p):
Martin v. Löwis05c075d2007-03-07 11:04:33 +0000162 return genericpath._splitext(p, sep, altsep, extsep)
163splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000164
165
166# Return the tail (basename) part of a path.
167
168def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000169 """Returns the final component of a pathname"""
170 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000171
172
173# Return the head (dirname) part of a path.
174
175def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000176 """Returns the directory component of a pathname"""
177 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000178
Guido van Rossum555915a1994-02-24 11:32:59 +0000179# Is a path a symbolic link?
180# This will always return false on systems where posix.lstat doesn't exist.
181
182def islink(path):
Jack Diederich7b604642006-08-26 18:42:06 +0000183 """Test for symbolic link.
184 On WindowsNT/95 and OS/2 always returns false
185 """
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000186 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000187
Jack Diederich7b604642006-08-26 18:42:06 +0000188# alias exists to lexists
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000189lexists = exists
190
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000191# Is a path a mount point? Either a root (with or without drive letter)
192# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000193
194def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000195 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000196 unc, rest = splitunc(path)
197 if unc:
198 return rest in ("", "/", "\\")
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000199 p = splitdrive(path)[1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000200 return len(p) == 1 and p[0] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +0000201
202
203# Directory tree walk.
204# For each directory under top (including top itself, but excluding
205# '.' and '..'), func(arg, dirname, filenames) is called, where
206# dirname is the name of the directory and filenames is the list
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +0000207# of files (and subdirectories etc.) in the directory.
Guido van Rossum555915a1994-02-24 11:32:59 +0000208# The func may modify the filenames list, to implement a filter,
209# or to impose a different order of visiting.
210
211def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000212 """Directory tree walk with callback function.
Guido van Rossum534972b1999-02-03 17:20:50 +0000213
Tim Peterscf5e6a42001-10-10 04:16:20 +0000214 For each directory in the directory tree rooted at top (including top
215 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
216 dirname is the name of the directory, and fnames a list of the names of
217 the files and subdirectories in dirname (excluding '.' and '..'). func
218 may modify the fnames list in-place (e.g. via del or slice assignment),
219 and walk will only recurse into the subdirectories whose names remain in
220 fnames; this can be used to implement a filter, or to impose a specific
221 order of visiting. No semantics are defined for, or required of, arg,
222 beyond that arg is always passed to func. It can be used, e.g., to pass
223 a filename pattern, or a mutable object designed to accumulate
224 statistics. Passing None for arg is common."""
Philip Jenveyd846f1d2009-05-08 02:28:39 +0000225 warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",
226 stacklevel=2)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000227 try:
228 names = os.listdir(top)
229 except os.error:
230 return
231 func(arg, top, names)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000232 for name in names:
Georg Brandle2a902c2008-01-06 14:17:36 +0000233 name = join(top, name)
234 if isdir(name):
235 walk(name, func, arg)
Guido van Rossum555915a1994-02-24 11:32:59 +0000236
237
238# Expand paths beginning with '~' or '~user'.
239# '~' means $HOME; '~user' means that user's home directory.
240# If the path doesn't begin with '~', or if the user or $HOME is unknown,
241# the path is returned unchanged (leaving error reporting to whatever
242# function is called with the expanded path as argument).
243# See also module 'glob' for expansion of *, ? and [...] in pathnames.
244# (A function should also be defined to do full *sh-style environment
245# variable expansion.)
246
247def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000248 """Expand ~ and ~user constructs.
249
250 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000251 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000252 return path
253 i, n = 1, len(path)
254 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000255 i = i + 1
Georg Brandl03b90d82007-03-13 22:07:36 +0000256
257 if 'HOME' in os.environ:
258 userhome = os.environ['HOME']
259 elif 'USERPROFILE' in os.environ:
260 userhome = os.environ['USERPROFILE']
261 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000262 return path
Georg Brandl03b90d82007-03-13 22:07:36 +0000263 else:
264 try:
265 drive = os.environ['HOMEDRIVE']
266 except KeyError:
267 drive = ''
268 userhome = join(drive, os.environ['HOMEPATH'])
269
270 if i != 1: #~user
271 userhome = join(dirname(userhome), path[1:i])
272
Guido van Rossum15e22e11997-12-05 19:03:01 +0000273 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000274
275
276# Expand paths containing shell variable substitutions.
277# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000278# - no expansion within single quotes
Georg Brandl03b90d82007-03-13 22:07:36 +0000279# - '$$' is translated into '$'
280# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000281# - ${varname} is accepted.
Georg Brandl03b90d82007-03-13 22:07:36 +0000282# - $varname is accepted.
283# - %varname% is accepted.
284# - varnames can be made out of letters, digits and the characters '_-'
Ezio Melottic2077b02011-03-16 12:34:31 +0200285# (though is not verified in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000286# XXX With COMMAND.COM you can use any characters in a variable name,
287# XXX except '^|<>='.
288
Tim Peters2344fae2001-01-15 00:50:52 +0000289def expandvars(path):
Georg Brandl03b90d82007-03-13 22:07:36 +0000290 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000291
292 Unknown variables are left unchanged."""
Georg Brandl03b90d82007-03-13 22:07:36 +0000293 if '$' not in path and '%' not in path:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000294 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000295 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000296 varchars = string.ascii_letters + string.digits + '_-'
Serhiy Storchaka2ac9d312014-02-19 23:27:37 +0200297 if isinstance(path, unicode):
298 encoding = sys.getfilesystemencoding()
299 def getenv(var):
300 return os.environ[var.encode(encoding)].decode(encoding)
301 else:
302 def getenv(var):
303 return os.environ[var]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000304 res = ''
305 index = 0
306 pathlen = len(path)
307 while index < pathlen:
308 c = path[index]
309 if c == '\'': # no expansion within single quotes
310 path = path[index + 1:]
311 pathlen = len(path)
312 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000313 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000314 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000315 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000316 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000317 index = pathlen - 1
Georg Brandl03b90d82007-03-13 22:07:36 +0000318 elif c == '%': # variable or '%'
319 if path[index + 1:index + 2] == '%':
320 res = res + c
321 index = index + 1
322 else:
323 path = path[index+1:]
324 pathlen = len(path)
325 try:
326 index = path.index('%')
327 except ValueError:
328 res = res + '%' + path
329 index = pathlen - 1
330 else:
331 var = path[:index]
Serhiy Storchaka2ac9d312014-02-19 23:27:37 +0200332 try:
333 res = res + getenv(var)
334 except KeyError:
Georg Brandl03b90d82007-03-13 22:07:36 +0000335 res = res + '%' + var + '%'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000336 elif c == '$': # variable or '$$'
337 if path[index + 1:index + 2] == '$':
338 res = res + c
339 index = index + 1
340 elif path[index + 1:index + 2] == '{':
341 path = path[index+2:]
342 pathlen = len(path)
343 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000344 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000345 var = path[:index]
Serhiy Storchaka2ac9d312014-02-19 23:27:37 +0200346 try:
347 res = res + getenv(var)
348 except KeyError:
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000349 res = res + '${' + var + '}'
Fred Drakeb4e460a2000-09-28 16:25:20 +0000350 except ValueError:
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000351 res = res + '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000352 index = pathlen - 1
353 else:
354 var = ''
355 index = index + 1
356 c = path[index:index + 1]
357 while c != '' and c in varchars:
358 var = var + c
359 index = index + 1
360 c = path[index:index + 1]
Serhiy Storchaka2ac9d312014-02-19 23:27:37 +0200361 try:
362 res = res + getenv(var)
363 except KeyError:
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000364 res = res + '$' + var
Guido van Rossum15e22e11997-12-05 19:03:01 +0000365 if c != '':
Sjoerd Mullender33a0a062007-01-16 16:42:38 +0000366 index = index - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000367 else:
368 res = res + c
369 index = index + 1
370 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000371
372
Tim Peters54a14a32001-08-30 22:05:26 +0000373# 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 +0000374# Previously, this function also truncated pathnames to 8+3 format,
375# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000376
377def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000378 """Normalize path, eliminating double slashes, etc."""
Ezio Melottib5689de2010-01-12 03:32:05 +0000379 # Preserve unicode (if path is unicode)
380 backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.')
Georg Brandle2773252010-08-01 19:14:56 +0000381 if path.startswith(('\\\\.\\', '\\\\?\\')):
382 # in the case of paths with these prefixes:
383 # \\.\ -> device names
384 # \\?\ -> literal paths
385 # do not do any normalization, but return the path unchanged
386 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000387 path = path.replace("/", "\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000388 prefix, path = splitdrive(path)
Brett Cannonbdc36272004-07-10 20:42:22 +0000389 # We need to be careful here. If the prefix is empty, and the path starts
390 # with a backslash, it could either be an absolute path on the current
391 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
392 # is therefore imperative NOT to collapse multiple backslashes blindly in
393 # that case.
394 # The code below preserves multiple backslashes when there is no drive
395 # letter. This means that the invalid filename \\\a\b is preserved
396 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
397 # is any better behaviour for such edge cases.
398 if prefix == '':
399 # No drive letter - preserve initial backslashes
400 while path[:1] == "\\":
Ezio Melottib5689de2010-01-12 03:32:05 +0000401 prefix = prefix + backslash
Brett Cannonbdc36272004-07-10 20:42:22 +0000402 path = path[1:]
403 else:
404 # We have a drive letter - collapse initial backslashes
405 if path.startswith("\\"):
Ezio Melottib5689de2010-01-12 03:32:05 +0000406 prefix = prefix + backslash
Brett Cannonbdc36272004-07-10 20:42:22 +0000407 path = path.lstrip("\\")
Fred Drakeb4e460a2000-09-28 16:25:20 +0000408 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000409 i = 0
410 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000411 if comps[i] in ('.', ''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000412 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000413 elif comps[i] == '..':
414 if i > 0 and comps[i-1] != '..':
415 del comps[i-1:i+1]
416 i -= 1
417 elif i == 0 and prefix.endswith("\\"):
418 del comps[i]
419 else:
420 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000421 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000422 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000423 # If the path is now empty, substitute '.'
424 if not prefix and not comps:
Ezio Melottib5689de2010-01-12 03:32:05 +0000425 comps.append(dot)
426 return prefix + backslash.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000427
428
429# Return an absolute path.
Tim Peters21fbd572006-04-21 21:18:10 +0000430try:
431 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000432
Tim Peters21fbd572006-04-21 21:18:10 +0000433except ImportError: # not running on Windows - mock up something sensible
434 def abspath(path):
435 """Return the absolute version of a path."""
436 if not isabs(path):
Ezio Melotti4cc80ca2010-02-20 08:09:39 +0000437 if isinstance(path, unicode):
438 cwd = os.getcwdu()
439 else:
440 cwd = os.getcwd()
441 path = join(cwd, path)
Tim Peters21fbd572006-04-21 21:18:10 +0000442 return normpath(path)
443
444else: # use native Windows method on Windows
445 def abspath(path):
446 """Return the absolute version of a path."""
447
448 if path: # Empty path must return current working directory.
449 try:
450 path = _getfullpathname(path)
451 except WindowsError:
452 pass # Bad path - return unchanged.
Ezio Melotti4cc80ca2010-02-20 08:09:39 +0000453 elif isinstance(path, unicode):
454 path = os.getcwdu()
Tim Peters21fbd572006-04-21 21:18:10 +0000455 else:
456 path = os.getcwd()
457 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000458
459# realpath is a no-op on systems without islink support
460realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000461# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000462supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
463 sys.getwindowsversion()[3] >= 2)
Collin Winter6f187742007-03-16 22:16:08 +0000464
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000465def _abspath_split(path):
466 abs = abspath(normpath(path))
467 prefix, rest = splitunc(abs)
468 is_unc = bool(prefix)
469 if not is_unc:
470 prefix, rest = splitdrive(abs)
471 return is_unc, prefix, [x for x in rest.split(sep) if x]
472
Collin Winter6f187742007-03-16 22:16:08 +0000473def relpath(path, start=curdir):
474 """Return a relative version of a path"""
475
476 if not path:
477 raise ValueError("no path specified")
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000478
479 start_is_unc, start_prefix, start_list = _abspath_split(start)
480 path_is_unc, path_prefix, path_list = _abspath_split(path)
481
482 if path_is_unc ^ start_is_unc:
483 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
484 % (path, start))
485 if path_prefix.lower() != start_prefix.lower():
486 if path_is_unc:
487 raise ValueError("path is on UNC root %s, start on UNC root %s"
488 % (path_prefix, start_prefix))
Collin Winter6f187742007-03-16 22:16:08 +0000489 else:
490 raise ValueError("path is on drive %s, start on drive %s"
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000491 % (path_prefix, start_prefix))
Collin Winter6f187742007-03-16 22:16:08 +0000492 # Work out how much of the filepath is shared by start and path.
Hirokazu Yamamoto8596ef72010-10-19 01:23:51 +0000493 i = 0
494 for e1, e2 in zip(start_list, path_list):
495 if e1.lower() != e2.lower():
Collin Winter6f187742007-03-16 22:16:08 +0000496 break
Collin Winter6f187742007-03-16 22:16:08 +0000497 i += 1
498
499 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Georg Brandl183a0842008-01-06 14:27:15 +0000500 if not rel_list:
501 return curdir
Collin Winter6f187742007-03-16 22:16:08 +0000502 return join(*rel_list)
Brian Curtincaea7e82011-06-08 19:29:53 -0500503
504try:
505 # The genericpath.isdir implementation uses os.stat and checks the mode
506 # attribute to tell whether or not the path is a directory.
507 # This is overkill on Windows - just pass the path to GetFileAttributes
508 # and check the attribute from there.
Brian Curtin5446f082011-06-09 10:00:42 -0500509 from nt import _isdir as isdir
Brian Curtincaea7e82011-06-08 19:29:53 -0500510except ImportError:
Brian Curtin5446f082011-06-09 10:00:42 -0500511 # Use genericpath.isdir as imported above.
512 pass