blob: f85a91435b90446d68f886ca05bdcae0eedbc897 [file] [log] [blame]
Guido van Rossum54f22ed2000-02-04 15:10:34 +00001"""Pathname and path-related operations for the Macintosh."""
Guido van Rossum217a5fa1990-12-26 15:40:07 +00002
Guido van Rossum5c1d2291998-03-03 21:49:01 +00003import os
Guido van Rossum217a5fa1990-12-26 15:40:07 +00004from stat import *
Guido van Rossumd8faa362007-04-27 19:54:29 +00005import genericpath
Thomas Wouters89f507f2006-12-13 04:49:30 +00006from genericpath import *
Victor Stinner89a1c932017-05-15 11:01:21 +02007import warnings
8
9warnings.warn('the macpath module is deprecated in 3.7 and will be removed '
10 'in 3.8', DeprecationWarning, stacklevel=2)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000011
Skip Montanaro17ab1232001-01-24 06:27:27 +000012__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
13 "basename","dirname","commonprefix","getsize","getmtime",
Georg Brandlf0de6a12005-08-22 18:02:59 +000014 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
Benjamin Petersond71ca412008-05-08 23:44:58 +000015 "expanduser","expandvars","normpath","abspath",
Skip Montanaro117910d2003-02-14 19:35:31 +000016 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000017 "devnull","realpath","supports_unicode_filenames"]
Guido van Rossumb5e05e91991-01-01 18:10:40 +000018
Skip Montanaro117910d2003-02-14 19:35:31 +000019# strings representing various path-related bits and pieces
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +000020# These are primarily for export; internally, they are hardcoded.
Skip Montanaro117910d2003-02-14 19:35:31 +000021curdir = ':'
22pardir = '::'
23extsep = '.'
24sep = ':'
25pathsep = '\n'
26defpath = ':'
27altsep = None
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000028devnull = 'Dev:Null'
Skip Montanaro117910d2003-02-14 19:35:31 +000029
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +000030def _get_colon(path):
31 if isinstance(path, bytes):
32 return b':'
33 else:
34 return ':'
35
Fred Drakeb4e460a2000-09-28 16:25:20 +000036# Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
Guido van Rossum599f2ed1992-01-14 18:28:18 +000037
Fred Drakeb4e460a2000-09-28 16:25:20 +000038def normcase(path):
Ezio Melotti5a3ef5b2010-06-25 10:56:11 +000039 if not isinstance(path, (bytes, str)):
40 raise TypeError("normcase() argument must be str or bytes, "
41 "not '{}'".format(path.__class__.__name__))
Fred Drakeb4e460a2000-09-28 16:25:20 +000042 return path.lower()
Guido van Rossum599f2ed1992-01-14 18:28:18 +000043
44
Guido van Rossum217a5fa1990-12-26 15:40:07 +000045def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000046 """Return true if a path is absolute.
47 On the Mac, relative paths begin with a colon,
48 but as a special case, paths with no colons at all are also relative.
49 Anything else is absolute (the string up to the first colon is the
50 volume name)."""
51
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +000052 colon = _get_colon(s)
53 return colon in s and s[:1] != colon
Guido van Rossum217a5fa1990-12-26 15:40:07 +000054
Guido van Rossumb5e05e91991-01-01 18:10:40 +000055
Barry Warsaw384d2491997-02-18 21:53:25 +000056def join(s, *p):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030057 try:
58 colon = _get_colon(s)
59 path = s
Serhiy Storchaka5bfc03f2015-05-19 11:00:07 +030060 if not p:
61 path[:0] + colon #23780: Ensure compatible data type even if p is null.
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030062 for t in p:
63 if (not path) or isabs(t):
64 path = t
65 continue
66 if t[:1] == colon:
67 t = t[1:]
68 if colon not in path:
69 path = colon + path
70 if path[-1:] != colon:
71 path = path + colon
72 path = path + t
73 return path
74 except (TypeError, AttributeError, BytesWarning):
75 genericpath._check_arg_types('join', s, *p)
76 raise
Guido van Rossum217a5fa1990-12-26 15:40:07 +000077
Guido van Rossumb5e05e91991-01-01 18:10:40 +000078
Guido van Rossumb5e05e91991-01-01 18:10:40 +000079def split(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000080 """Split a pathname into two parts: the directory leading up to the final
81 bit, and the basename (the filename, without colons, in that directory).
82 The result (s, t) is such that join(s, t) yields the original argument."""
Guido van Rossumb5e05e91991-01-01 18:10:40 +000083
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +000084 colon = _get_colon(s)
85 if colon not in s: return s[:0], s
86 col = 0
Guido van Rossum54f22ed2000-02-04 15:10:34 +000087 for i in range(len(s)):
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +000088 if s[i:i+1] == colon: col = i + 1
89 path, file = s[:col-1], s[col:]
90 if path and not colon in path:
91 path = path + colon
Guido van Rossum54f22ed2000-02-04 15:10:34 +000092 return path, file
Guido van Rossumb5e05e91991-01-01 18:10:40 +000093
Guido van Rossuma48bf791996-07-23 02:28:32 +000094
95def splitext(p):
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +000096 if isinstance(p, bytes):
97 return genericpath._splitext(p, b':', altsep, b'.')
98 else:
99 return genericpath._splitext(p, sep, altsep, extsep)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000100splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum0ec31261995-08-10 18:09:16 +0000101
102def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000103 """Split a pathname into a drive specification and the rest of the
104 path. Useful on DOS/Windows/NT; on the Mac, the drive is always
105 empty (don't use the volume name -- it doesn't have the same
106 syntactic and semantic oddities as DOS drive letters, such as there
107 being a separate current directory per drive)."""
108
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000109 return p[:0], p
Guido van Rossum0ec31261995-08-10 18:09:16 +0000110
111
Guido van Rossumc629d341992-11-05 10:43:02 +0000112# Short interfaces to split()
113
114def dirname(s): return split(s)[0]
115def basename(s): return split(s)[1]
116
Jack Jansen791f7d42003-01-15 22:45:48 +0000117def ismount(s):
Tim Peters2c60f7a2003-01-29 03:49:43 +0000118 if not isabs(s):
119 return False
120 components = split(s)
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000121 return len(components) == 2 and not components[1]
Guido van Rossumc629d341992-11-05 10:43:02 +0000122
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000123def islink(s):
Jack Jansen992d58b2002-04-22 13:55:43 +0000124 """Return true if the pathname refers to a symbolic link."""
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000125
Jack Jansen992d58b2002-04-22 13:55:43 +0000126 try:
Jack Jansen98fc6832003-02-27 23:18:46 +0000127 import Carbon.File
128 return Carbon.File.ResolveAliasFile(s, 0)[2]
Jack Jansen992d58b2002-04-22 13:55:43 +0000129 except:
130 return False
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000131
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000132# Is `stat`/`lstat` a meaningful difference on the Mac? This is safe in any
133# case.
134
135def lexists(path):
136 """Test whether a path exists. Returns True for broken symbolic links"""
137
138 try:
139 st = os.lstat(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200140 except OSError:
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000141 return False
142 return True
143
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000144def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000145 """Dummy to retain interface-compatibility with other operating systems."""
146 return path
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000147
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000148
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000149def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000150 """Dummy to retain interface-compatibility with other operating systems."""
151 return path
Guido van Rossum0ec31261995-08-10 18:09:16 +0000152
Neal Norwitz93cf79f2002-03-31 14:06:41 +0000153class norm_error(Exception):
154 """Path cannot be normalized"""
Guido van Rossumc629d341992-11-05 10:43:02 +0000155
156def normpath(s):
Jack Jansen2fc01092000-08-06 21:18:35 +0000157 """Normalize a pathname. Will return the same result for
158 equivalent paths."""
Jack Jansena68bfe21995-08-07 14:09:27 +0000159
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000160 colon = _get_colon(s)
Jack Jansen2fc01092000-08-06 21:18:35 +0000161
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000162 if colon not in s:
163 return colon + s
164
165 comps = s.split(colon)
Jack Jansen2fc01092000-08-06 21:18:35 +0000166 i = 1
167 while i < len(comps)-1:
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000168 if not comps[i] and comps[i-1]:
Jack Jansen2fc01092000-08-06 21:18:35 +0000169 if i > 1:
170 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000171 i = i - 1
Jack Jansen2fc01092000-08-06 21:18:35 +0000172 else:
173 # best way to handle this is to raise an exception
Collin Winterce36ad82007-08-30 01:19:48 +0000174 raise norm_error('Cannot use :: immediately after volume name')
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000175 else:
Jack Jansen2fc01092000-08-06 21:18:35 +0000176 i = i + 1
177
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000178 s = colon.join(comps)
Jack Jansen2fc01092000-08-06 21:18:35 +0000179
180 # remove trailing ":" except for ":" and "Volume:"
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000181 if s[-1:] == colon and len(comps) > 2 and s != colon*len(s):
Jack Jansen2fc01092000-08-06 21:18:35 +0000182 s = s[:-1]
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000183 return s
Guido van Rossum0ec31261995-08-10 18:09:16 +0000184
Guido van Rossume294cf61999-01-29 18:05:18 +0000185def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000186 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000187 if not isabs(path):
Florent Xicluna19b02d42010-03-08 12:25:35 +0000188 if isinstance(path, bytes):
189 cwd = os.getcwdb()
190 else:
191 cwd = os.getcwd()
192 path = join(cwd, path)
Guido van Rossume294cf61999-01-29 18:05:18 +0000193 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000194
195# realpath is a no-op on systems without islink support
Jack Jansen992d58b2002-04-22 13:55:43 +0000196def realpath(path):
Tim Peters8ac14952002-05-23 15:15:30 +0000197 path = abspath(path)
198 try:
Jack Jansen98fc6832003-02-27 23:18:46 +0000199 import Carbon.File
Brett Cannoncd171c82013-07-04 17:43:24 -0400200 except ImportError:
Tim Peters8ac14952002-05-23 15:15:30 +0000201 return path
202 if not path:
203 return path
Amaury Forgeot d'Arcb186f342008-10-03 21:57:20 +0000204 colon = _get_colon(path)
205 components = path.split(colon)
206 path = components[0] + colon
Tim Peters8ac14952002-05-23 15:15:30 +0000207 for c in components[1:]:
208 path = join(path, c)
Florent Xicluna54467e02010-03-21 12:29:50 +0000209 try:
210 path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname()
211 except Carbon.File.Error:
212 pass
Tim Peters8ac14952002-05-23 15:15:30 +0000213 return path
Mark Hammond8696ebc2002-10-08 02:44:31 +0000214
Victor Stinnerccb706c2010-09-13 19:41:36 +0000215supports_unicode_filenames = True