blob: 9cc5ca738d4a54fbb9f90180e8e479d1f27e3f60 [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",
Brian Curtind40e6f72010-07-08 21:39:08 +000019 "extsep","devnull","realpath","supports_unicode_filenames","relpath",
Serhiy Storchaka38220932015-03-31 15:31:53 +030020 "samefile", "sameopenfile", "samestat", "commonpath"]
Guido van Rossum555915a1994-02-24 11:32:59 +000021
Skip Montanaro117910d2003-02-14 19:35:31 +000022# strings representing various path-related bits and pieces
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000023# These are primarily for export; internally, they are hardcoded.
Skip Montanaro117910d2003-02-14 19:35:31 +000024curdir = '.'
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'
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000033devnull = 'nul'
Skip Montanaro117910d2003-02-14 19:35:31 +000034
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000035def _get_bothseps(path):
36 if isinstance(path, bytes):
37 return b'\\/'
38 else:
39 return '\\/'
40
Guido van Rossume2ad88c1997-08-12 14:46:58 +000041# Normalize the case of a pathname and map slashes to backslashes.
42# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000043# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000044
Guido van Rossum555915a1994-02-24 11:32:59 +000045def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000046 """Normalize case of pathname.
47
Guido van Rossum534972b1999-02-03 17:20:50 +000048 Makes all characters lowercase and all slashes into backslashes."""
Serhiy Storchaka8518b792014-07-23 20:43:13 +030049 try:
50 if isinstance(s, bytes):
51 return s.replace(b'/', b'\\').lower()
52 else:
53 return s.replace('/', '\\').lower()
54 except (TypeError, AttributeError):
55 if not isinstance(s, (bytes, str)):
56 raise TypeError("normcase() argument must be str or bytes, "
57 "not %r" % s.__class__.__name__) from None
58 raise
Guido van Rossum555915a1994-02-24 11:32:59 +000059
Guido van Rossum77e1db31997-06-02 23:11:57 +000060
Fred Drakeef0b5dd2000-02-17 17:30:40 +000061# Return whether a path is absolute.
Mark Hammond5a607a32009-05-06 08:04:54 +000062# Trivial in Posix, harder on Windows.
63# For Windows it is absolute if it starts with a slash or backslash (current
64# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
Guido van Rossum534972b1999-02-03 17:20:50 +000065# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000066
67def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000068 """Test whether a path is absolute"""
69 s = splitdrive(s)[1]
Serhiy Storchaka8518b792014-07-23 20:43:13 +030070 return len(s) > 0 and s[0] in _get_bothseps(s)
Guido van Rossum555915a1994-02-24 11:32:59 +000071
72
Guido van Rossum77e1db31997-06-02 23:11:57 +000073# Join two (or more) paths.
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020074def join(path, *paths):
Serhiy Storchaka8518b792014-07-23 20:43:13 +030075 if isinstance(path, bytes):
76 sep = b'\\'
77 seps = b'\\/'
78 colon = b':'
79 else:
80 sep = '\\'
81 seps = '\\/'
82 colon = ':'
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030083 try:
Serhiy Storchaka5bfc03f2015-05-19 11:00:07 +030084 if not paths:
85 path[:0] + sep #23780: Ensure compatible data type even if p is null.
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030086 result_drive, result_path = splitdrive(path)
87 for p in paths:
88 p_drive, p_path = splitdrive(p)
89 if p_path and p_path[0] in seps:
90 # Second path is absolute
91 if p_drive or not result_drive:
92 result_drive = p_drive
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020093 result_path = p_path
94 continue
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030095 elif p_drive and p_drive != result_drive:
96 if p_drive.lower() != result_drive.lower():
97 # Different drives => ignore the first path entirely
98 result_drive = p_drive
99 result_path = p_path
100 continue
101 # Same drive in different case
102 result_drive = p_drive
103 # Second path is relative to the first
104 if result_path and result_path[-1] not in seps:
105 result_path = result_path + sep
106 result_path = result_path + p_path
107 ## add separator between UNC and non-absolute path
108 if (result_path and result_path[0] not in seps and
109 result_drive and result_drive[-1:] != colon):
110 return result_drive + sep + result_path
111 return result_drive + result_path
112 except (TypeError, AttributeError, BytesWarning):
113 genericpath._check_arg_types('join', path, *paths)
114 raise
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):
Mark Hammond5a607a32009-05-06 08:04:54 +0000121 """Split a pathname into drive/UNC sharepoint and relative path specifiers.
122 Returns a 2-tuple (drive_or_unc, path); either part may be empty.
123
124 If you assign
125 result = splitdrive(p)
126 It is always true that:
127 result[0] + result[1] == p
128
129 If the path contained a drive letter, drive_or_unc will contain everything
130 up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
131
132 If the path contained a UNC path, the drive_or_unc will contain the host name
133 and share up to but not including the fourth directory separator character.
134 e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
135
136 Paths cannot contain both a drive letter and a UNC path.
137
138 """
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300139 if len(p) >= 2:
140 if isinstance(p, bytes):
141 sep = b'\\'
142 altsep = b'/'
143 colon = b':'
144 else:
145 sep = '\\'
146 altsep = '/'
147 colon = ':'
148 normp = p.replace(altsep, sep)
Mark Hammond5a607a32009-05-06 08:04:54 +0000149 if (normp[0:2] == sep*2) and (normp[2:3] != sep):
150 # is a UNC path:
151 # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
152 # \\machine\mountpoint\directory\etc\...
153 # directory ^^^^^^^^^^^^^^^
154 index = normp.find(sep, 2)
155 if index == -1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300156 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000157 index2 = normp.find(sep, index + 1)
158 # a UNC path can't have two slashes in a row
159 # (after the initial two)
160 if index2 == index + 1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300161 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000162 if index2 == -1:
163 index2 = len(p)
164 return p[:index2], p[index2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300165 if normp[1:2] == colon:
Mark Hammond5a607a32009-05-06 08:04:54 +0000166 return p[:2], p[2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300167 return p[:0], p
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000168
169
170# Parse UNC paths
171def splitunc(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000172 """Deprecated since Python 3.1. Please use splitdrive() instead;
173 it now handles UNC paths.
174
175 Split a pathname into UNC mount point and relative path specifiers.
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000176
177 Return a 2-tuple (unc, rest); either part may be empty.
178 If unc is not empty, it has the form '//host/mount' (or similar
179 using backslashes). unc+rest is always the input path.
180 Paths containing drive letters never have an UNC part.
181 """
Mark Hammond5a607a32009-05-06 08:04:54 +0000182 import warnings
183 warnings.warn("ntpath.splitunc is deprecated, use ntpath.splitdrive instead",
Serhiy Storchaka593568b2013-12-16 15:13:28 +0200184 DeprecationWarning, 2)
185 drive, path = splitdrive(p)
186 if len(drive) == 2:
187 # Drive letter present
188 return p[:0], p
189 return drive, path
Guido van Rossum555915a1994-02-24 11:32:59 +0000190
191
192# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000193# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000194# join(head, tail) == p holds.
195# The resulting head won't end in '/' unless it is the root.
196
197def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000198 """Split a pathname.
199
200 Return tuple (head, tail) where tail is everything after the final slash.
201 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000202
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000203 seps = _get_bothseps(p)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000204 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000205 # set i to index beyond p's last slash
206 i = len(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000207 while i and p[i-1] not in seps:
Georg Brandl599b65d2010-07-23 08:46:35 +0000208 i -= 1
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000209 head, tail = p[:i], p[i:] # now tail has no slashes
210 # remove trailing slashes from head, unless it's all slashes
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300211 head = head.rstrip(seps) or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000212 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000213
214
215# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000216# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000217# pathname component; the root is everything before that.
218# It is always true that root + ext == p.
219
220def splitext(p):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300221 if isinstance(p, bytes):
222 return genericpath._splitext(p, b'\\', b'/', b'.')
223 else:
224 return genericpath._splitext(p, '\\', '/', '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000225splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000226
227
228# Return the tail (basename) part of a path.
229
230def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000231 """Returns the final component of a pathname"""
232 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000233
234
235# Return the head (dirname) part of a path.
236
237def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000238 """Returns the directory component of a pathname"""
239 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000240
Guido van Rossum555915a1994-02-24 11:32:59 +0000241# Is a path a symbolic link?
Brian Curtind40e6f72010-07-08 21:39:08 +0000242# This will always return false on systems where os.lstat doesn't exist.
Guido van Rossum555915a1994-02-24 11:32:59 +0000243
244def islink(path):
Brian Curtind40e6f72010-07-08 21:39:08 +0000245 """Test whether a path is a symbolic link.
Jesus Ceaf1af7052012-10-05 02:48:46 +0200246 This will always return false for Windows prior to 6.0.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000247 """
Brian Curtind40e6f72010-07-08 21:39:08 +0000248 try:
249 st = os.lstat(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200250 except (OSError, AttributeError):
Brian Curtind40e6f72010-07-08 21:39:08 +0000251 return False
252 return stat.S_ISLNK(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000253
Brian Curtind40e6f72010-07-08 21:39:08 +0000254# Being true for dangling symbolic links is also useful.
255
256def lexists(path):
257 """Test whether a path exists. Returns True for broken symbolic links"""
258 try:
259 st = os.lstat(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200260 except OSError:
Brian Curtind40e6f72010-07-08 21:39:08 +0000261 return False
262 return True
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000263
Tim Golden6b528062013-08-01 12:44:00 +0100264# Is a path a mount point?
265# Any drive letter root (eg c:\)
266# Any share UNC (eg \\server\share)
267# Any volume mounted on a filesystem folder
268#
269# No one method detects all three situations. Historically we've lexically
270# detected drive letter roots and share UNCs. The canonical approach to
271# detecting mounted volumes (querying the reparse tag) fails for the most
272# common case: drive letter roots. The alternative which uses GetVolumePathName
273# fails if the drive letter is the result of a SUBST.
274try:
275 from nt import _getvolumepathname
276except ImportError:
277 _getvolumepathname = None
Guido van Rossum555915a1994-02-24 11:32:59 +0000278def ismount(path):
Tim Golden6b528062013-08-01 12:44:00 +0100279 """Test whether a path is a mount point (a drive root, the root of a
280 share, or a mounted volume)"""
Benjamin Peterson48e24782009-03-29 13:02:52 +0000281 seps = _get_bothseps(path)
Tim Golden6b528062013-08-01 12:44:00 +0100282 path = abspath(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000283 root, rest = splitdrive(path)
284 if root and root[0] in seps:
285 return (not rest) or (rest in seps)
Tim Golden6b528062013-08-01 12:44:00 +0100286 if rest in seps:
287 return True
288
289 if _getvolumepathname:
290 return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
291 else:
292 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000293
294
Guido van Rossum555915a1994-02-24 11:32:59 +0000295# Expand paths beginning with '~' or '~user'.
296# '~' means $HOME; '~user' means that user's home directory.
297# If the path doesn't begin with '~', or if the user or $HOME is unknown,
298# the path is returned unchanged (leaving error reporting to whatever
299# function is called with the expanded path as argument).
300# See also module 'glob' for expansion of *, ? and [...] in pathnames.
301# (A function should also be defined to do full *sh-style environment
302# variable expansion.)
303
304def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000305 """Expand ~ and ~user constructs.
306
307 If user or $HOME is unknown, do nothing."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000308 if isinstance(path, bytes):
309 tilde = b'~'
310 else:
311 tilde = '~'
312 if not path.startswith(tilde):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000313 return path
314 i, n = 1, len(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000315 while i < n and path[i] not in _get_bothseps(path):
Georg Brandl599b65d2010-07-23 08:46:35 +0000316 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000317
318 if 'HOME' in os.environ:
319 userhome = os.environ['HOME']
320 elif 'USERPROFILE' in os.environ:
321 userhome = os.environ['USERPROFILE']
322 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000323 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000324 else:
325 try:
326 drive = os.environ['HOMEDRIVE']
327 except KeyError:
328 drive = ''
329 userhome = join(drive, os.environ['HOMEPATH'])
330
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000331 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300332 userhome = os.fsencode(userhome)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000333
Guido van Rossumd8faa362007-04-27 19:54:29 +0000334 if i != 1: #~user
335 userhome = join(dirname(userhome), path[1:i])
336
Guido van Rossum15e22e11997-12-05 19:03:01 +0000337 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000338
339
340# Expand paths containing shell variable substitutions.
341# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000342# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000343# - '$$' is translated into '$'
344# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000345# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000346# - $varname is accepted.
347# - %varname% is accepted.
348# - varnames can be made out of letters, digits and the characters '_-'
Ezio Melotti13925002011-03-16 11:05:33 +0200349# (though is not verified in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000350# XXX With COMMAND.COM you can use any characters in a variable name,
351# XXX except '^|<>='.
352
Tim Peters2344fae2001-01-15 00:50:52 +0000353def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000354 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000355
356 Unknown variables are left unchanged."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000357 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300358 if b'$' not in path and b'%' not in path:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000359 return path
360 import string
361 varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000362 quote = b'\''
363 percent = b'%'
364 brace = b'{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300365 rbrace = b'}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000366 dollar = b'$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200367 environ = getattr(os, 'environb', None)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000368 else:
369 if '$' not in path and '%' not in path:
370 return path
371 import string
372 varchars = string.ascii_letters + string.digits + '_-'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000373 quote = '\''
374 percent = '%'
375 brace = '{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300376 rbrace = '}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000377 dollar = '$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200378 environ = os.environ
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000379 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000380 index = 0
381 pathlen = len(path)
382 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000383 c = path[index:index+1]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000384 if c == quote: # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000385 path = path[index + 1:]
386 pathlen = len(path)
387 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000388 index = path.index(c)
Georg Brandl599b65d2010-07-23 08:46:35 +0000389 res += c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000390 except ValueError:
Serhiy Storchaka1b87ae02015-03-25 16:40:15 +0200391 res += c + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000392 index = pathlen - 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000393 elif c == percent: # variable or '%'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000394 if path[index + 1:index + 2] == percent:
Georg Brandl599b65d2010-07-23 08:46:35 +0000395 res += c
396 index += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000397 else:
398 path = path[index+1:]
399 pathlen = len(path)
400 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000401 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000402 except ValueError:
Georg Brandl599b65d2010-07-23 08:46:35 +0000403 res += percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000404 index = pathlen - 1
405 else:
406 var = path[:index]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200407 try:
408 if environ is None:
409 value = os.fsencode(os.environ[os.fsdecode(var)])
410 else:
411 value = environ[var]
412 except KeyError:
413 value = percent + var + percent
Georg Brandl599b65d2010-07-23 08:46:35 +0000414 res += value
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000415 elif c == dollar: # variable or '$$'
416 if path[index + 1:index + 2] == dollar:
Georg Brandl599b65d2010-07-23 08:46:35 +0000417 res += c
418 index += 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000419 elif path[index + 1:index + 2] == brace:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000420 path = path[index+2:]
421 pathlen = len(path)
422 try:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300423 index = path.index(rbrace)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000424 except ValueError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300425 res += dollar + brace + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000426 index = pathlen - 1
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200427 else:
428 var = path[:index]
429 try:
430 if environ is None:
431 value = os.fsencode(os.environ[os.fsdecode(var)])
432 else:
433 value = environ[var]
434 except KeyError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300435 value = dollar + brace + var + rbrace
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200436 res += value
Guido van Rossum15e22e11997-12-05 19:03:01 +0000437 else:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200438 var = path[:0]
Georg Brandl599b65d2010-07-23 08:46:35 +0000439 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000440 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000441 while c and c in varchars:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200442 var += c
Georg Brandl599b65d2010-07-23 08:46:35 +0000443 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000444 c = path[index:index + 1]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200445 try:
446 if environ is None:
447 value = os.fsencode(os.environ[os.fsdecode(var)])
448 else:
449 value = environ[var]
450 except KeyError:
451 value = dollar + var
Georg Brandl599b65d2010-07-23 08:46:35 +0000452 res += value
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000453 if c:
Georg Brandl599b65d2010-07-23 08:46:35 +0000454 index -= 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000455 else:
Georg Brandl599b65d2010-07-23 08:46:35 +0000456 res += c
457 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000458 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000459
460
Tim Peters54a14a32001-08-30 22:05:26 +0000461# 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 +0000462# Previously, this function also truncated pathnames to 8+3 format,
463# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000464
465def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000466 """Normalize path, eliminating double slashes, etc."""
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300467 if isinstance(path, bytes):
468 sep = b'\\'
469 altsep = b'/'
470 curdir = b'.'
471 pardir = b'..'
472 special_prefixes = (b'\\\\.\\', b'\\\\?\\')
473 else:
474 sep = '\\'
475 altsep = '/'
476 curdir = '.'
477 pardir = '..'
478 special_prefixes = ('\\\\.\\', '\\\\?\\')
Georg Brandlcfb68212010-07-31 21:40:15 +0000479 if path.startswith(special_prefixes):
480 # in the case of paths with these prefixes:
481 # \\.\ -> device names
482 # \\?\ -> literal paths
483 # do not do any normalization, but return the path unchanged
484 return path
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300485 path = path.replace(altsep, sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000486 prefix, path = splitdrive(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000487
488 # collapse initial backslashes
489 if path.startswith(sep):
Georg Brandl599b65d2010-07-23 08:46:35 +0000490 prefix += sep
Mark Hammond5a607a32009-05-06 08:04:54 +0000491 path = path.lstrip(sep)
492
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000493 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000494 i = 0
495 while i < len(comps):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300496 if not comps[i] or comps[i] == curdir:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000497 del comps[i]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300498 elif comps[i] == pardir:
499 if i > 0 and comps[i-1] != pardir:
Tim Peters54a14a32001-08-30 22:05:26 +0000500 del comps[i-1:i+1]
501 i -= 1
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300502 elif i == 0 and prefix.endswith(sep):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000503 del comps[i]
504 else:
505 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000506 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000507 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000508 # If the path is now empty, substitute '.'
509 if not prefix and not comps:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300510 comps.append(curdir)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000511 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000512
513
514# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000515try:
516 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000517
Brett Cannoncd171c82013-07-04 17:43:24 -0400518except ImportError: # not running on Windows - mock up something sensible
Thomas Wouters477c8d52006-05-27 19:21:47 +0000519 def abspath(path):
520 """Return the absolute version of a path."""
521 if not isabs(path):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000522 if isinstance(path, bytes):
523 cwd = os.getcwdb()
524 else:
525 cwd = os.getcwd()
526 path = join(cwd, path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000527 return normpath(path)
528
529else: # use native Windows method on Windows
530 def abspath(path):
531 """Return the absolute version of a path."""
532
533 if path: # Empty path must return current working directory.
534 try:
535 path = _getfullpathname(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200536 except OSError:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000537 pass # Bad path - return unchanged.
Florent Xiclunaad8c5ca2010-03-08 14:44:41 +0000538 elif isinstance(path, bytes):
539 path = os.getcwdb()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000540 else:
541 path = os.getcwd()
542 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000543
544# realpath is a no-op on systems without islink support
545realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000546# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000547supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
548 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000549
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300550def relpath(path, start=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000551 """Return a relative version of a path"""
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300552 if isinstance(path, bytes):
553 sep = b'\\'
554 curdir = b'.'
555 pardir = b'..'
556 else:
557 sep = '\\'
558 curdir = '.'
559 pardir = '..'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000560
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300561 if start is None:
562 start = curdir
Guido van Rossumd8faa362007-04-27 19:54:29 +0000563
564 if not path:
565 raise ValueError("no path specified")
Mark Hammond5a607a32009-05-06 08:04:54 +0000566
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300567 try:
568 start_abs = abspath(normpath(start))
569 path_abs = abspath(normpath(path))
570 start_drive, start_rest = splitdrive(start_abs)
571 path_drive, path_rest = splitdrive(path_abs)
572 if normcase(start_drive) != normcase(path_drive):
573 raise ValueError("path is on mount %r, start on mount %r" % (
574 path_drive, start_drive))
Mark Hammond5a607a32009-05-06 08:04:54 +0000575
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300576 start_list = [x for x in start_rest.split(sep) if x]
577 path_list = [x for x in path_rest.split(sep) if x]
578 # Work out how much of the filepath is shared by start and path.
579 i = 0
580 for e1, e2 in zip(start_list, path_list):
581 if normcase(e1) != normcase(e2):
582 break
583 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000584
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300585 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
586 if not rel_list:
587 return curdir
588 return join(*rel_list)
Serhiy Storchakae4f47082014-10-04 16:09:02 +0300589 except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300590 genericpath._check_arg_types('relpath', path, start)
591 raise
Brian Curtind40e6f72010-07-08 21:39:08 +0000592
593
Serhiy Storchaka38220932015-03-31 15:31:53 +0300594# Return the longest common sub-path of the sequence of paths given as input.
595# The function is case-insensitive and 'separator-insensitive', i.e. if the
596# only difference between two paths is the use of '\' versus '/' as separator,
597# they are deemed to be equal.
598#
599# However, the returned path will have the standard '\' separator (even if the
600# given paths had the alternative '/' separator) and will have the case of the
601# first path given in the sequence. Additionally, any trailing separator is
602# stripped from the returned path.
603
604def commonpath(paths):
605 """Given a sequence of path names, returns the longest common sub-path."""
606
607 if not paths:
608 raise ValueError('commonpath() arg is an empty sequence')
609
610 if isinstance(paths[0], bytes):
611 sep = b'\\'
612 altsep = b'/'
613 curdir = b'.'
614 else:
615 sep = '\\'
616 altsep = '/'
617 curdir = '.'
618
619 try:
620 drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
621 split_paths = [p.split(sep) for d, p in drivesplits]
622
623 try:
624 isabs, = set(p[:1] == sep for d, p in drivesplits)
625 except ValueError:
626 raise ValueError("Can't mix absolute and relative paths") from None
627
628 # Check that all drive letters or UNC paths match. The check is made only
629 # now otherwise type errors for mixing strings and bytes would not be
630 # caught.
631 if len(set(d for d, p in drivesplits)) != 1:
632 raise ValueError("Paths don't have the same drive")
633
634 drive, path = splitdrive(paths[0].replace(altsep, sep))
635 common = path.split(sep)
636 common = [c for c in common if c and c != curdir]
637
638 split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
639 s1 = min(split_paths)
640 s2 = max(split_paths)
641 for i, c in enumerate(s1):
642 if c != s2[i]:
643 common = common[:i]
644 break
645 else:
646 common = common[:len(s1)]
647
648 prefix = drive + sep if isabs else drive
649 return prefix + sep.join(common)
650 except (TypeError, AttributeError):
651 genericpath._check_arg_types('commonpath', *paths)
652 raise
653
654
Brian Curtind40e6f72010-07-08 21:39:08 +0000655# determine if two files are in fact the same file
Brian Curtin0dac8082010-09-23 20:38:14 +0000656try:
Brian Curtine8e80422010-09-24 13:56:34 +0000657 # GetFinalPathNameByHandle is available starting with Windows 6.0.
658 # Windows XP and non-Windows OS'es will mock _getfinalpathname.
659 if sys.getwindowsversion()[:2] >= (6, 0):
660 from nt import _getfinalpathname
661 else:
662 raise ImportError
663except (AttributeError, ImportError):
Brian Curtin0dac8082010-09-23 20:38:14 +0000664 # On Windows XP and earlier, two files are the same if their absolute
665 # pathnames are the same.
Brian Curtine8e80422010-09-24 13:56:34 +0000666 # Non-Windows operating systems fake this method with an XP
667 # approximation.
Brian Curtin0dac8082010-09-23 20:38:14 +0000668 def _getfinalpathname(f):
Ronald Oussoren6355c162011-05-06 17:11:07 +0200669 return normcase(abspath(f))
Brian Curtin0dac8082010-09-23 20:38:14 +0000670
Brian Curtin9c669cc2011-06-08 18:17:18 -0500671
672try:
673 # The genericpath.isdir implementation uses os.stat and checks the mode
674 # attribute to tell whether or not the path is a directory.
675 # This is overkill on Windows - just pass the path to GetFileAttributes
676 # and check the attribute from there.
Brian Curtin95d028f2011-06-09 09:10:38 -0500677 from nt import _isdir as isdir
Brett Cannoncd171c82013-07-04 17:43:24 -0400678except ImportError:
Brian Curtin95d028f2011-06-09 09:10:38 -0500679 # Use genericpath.isdir as imported above.
680 pass