blob: f54ffa07d71a654c4d252249384e52834efcdbf2 [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 *
Martin v. Löwis05c075d2007-03-07 11:04:33 +00005import genericpath
Jack Diederich7b604642006-08-26 18:42:06 +00006from genericpath import *
Guido van Rossum217a5fa1990-12-26 15:40:07 +00007
Skip Montanaro17ab1232001-01-24 06:27:27 +00008__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
9 "basename","dirname","commonprefix","getsize","getmtime",
Georg Brandlf0de6a12005-08-22 18:02:59 +000010 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
Mark Hammond8696ebc2002-10-08 02:44:31 +000011 "walk","expanduser","expandvars","normpath","abspath",
Skip Montanaro117910d2003-02-14 19:35:31 +000012 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000013 "devnull","realpath","supports_unicode_filenames"]
Guido van Rossumb5e05e91991-01-01 18:10:40 +000014
Skip Montanaro117910d2003-02-14 19:35:31 +000015# strings representing various path-related bits and pieces
16curdir = ':'
17pardir = '::'
18extsep = '.'
19sep = ':'
20pathsep = '\n'
21defpath = ':'
22altsep = None
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000023devnull = 'Dev:Null'
Skip Montanaro117910d2003-02-14 19:35:31 +000024
Fred Drakeb4e460a2000-09-28 16:25:20 +000025# Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
Guido van Rossum599f2ed1992-01-14 18:28:18 +000026
Fred Drakeb4e460a2000-09-28 16:25:20 +000027def normcase(path):
28 return path.lower()
Guido van Rossum599f2ed1992-01-14 18:28:18 +000029
30
Guido van Rossum217a5fa1990-12-26 15:40:07 +000031def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000032 """Return true if a path is absolute.
33 On the Mac, relative paths begin with a colon,
34 but as a special case, paths with no colons at all are also relative.
35 Anything else is absolute (the string up to the first colon is the
36 volume name)."""
37
Fred Drake8152d322000-12-12 23:20:45 +000038 return ':' in s and s[0] != ':'
Guido van Rossum217a5fa1990-12-26 15:40:07 +000039
Guido van Rossumb5e05e91991-01-01 18:10:40 +000040
Barry Warsaw384d2491997-02-18 21:53:25 +000041def join(s, *p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000042 path = s
43 for t in p:
44 if (not s) or isabs(t):
45 path = t
46 continue
47 if t[:1] == ':':
48 t = t[1:]
49 if ':' not in path:
50 path = ':' + path
Fred Drake8152d322000-12-12 23:20:45 +000051 if path[-1:] != ':':
Guido van Rossum54f22ed2000-02-04 15:10:34 +000052 path = path + ':'
53 path = path + t
54 return path
Guido van Rossum217a5fa1990-12-26 15:40:07 +000055
Guido van Rossumb5e05e91991-01-01 18:10:40 +000056
Guido van Rossumb5e05e91991-01-01 18:10:40 +000057def split(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000058 """Split a pathname into two parts: the directory leading up to the final
59 bit, and the basename (the filename, without colons, in that directory).
60 The result (s, t) is such that join(s, t) yields the original argument."""
Guido van Rossumb5e05e91991-01-01 18:10:40 +000061
Guido van Rossum54f22ed2000-02-04 15:10:34 +000062 if ':' not in s: return '', s
63 colon = 0
64 for i in range(len(s)):
Fred Drakeb4e460a2000-09-28 16:25:20 +000065 if s[i] == ':': colon = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +000066 path, file = s[:colon-1], s[colon:]
67 if path and not ':' in path:
68 path = path + ':'
69 return path, file
Guido van Rossumb5e05e91991-01-01 18:10:40 +000070
Guido van Rossuma48bf791996-07-23 02:28:32 +000071
72def splitext(p):
Martin v. Löwis05c075d2007-03-07 11:04:33 +000073 return genericpath._splitext(p, sep, altsep, extsep)
74splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum0ec31261995-08-10 18:09:16 +000075
76def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000077 """Split a pathname into a drive specification and the rest of the
78 path. Useful on DOS/Windows/NT; on the Mac, the drive is always
79 empty (don't use the volume name -- it doesn't have the same
80 syntactic and semantic oddities as DOS drive letters, such as there
81 being a separate current directory per drive)."""
82
83 return '', p
Guido van Rossum0ec31261995-08-10 18:09:16 +000084
85
Guido van Rossumc629d341992-11-05 10:43:02 +000086# Short interfaces to split()
87
88def dirname(s): return split(s)[0]
89def basename(s): return split(s)[1]
90
Jack Jansen791f7d42003-01-15 22:45:48 +000091def ismount(s):
Tim Peters2c60f7a2003-01-29 03:49:43 +000092 if not isabs(s):
93 return False
94 components = split(s)
95 return len(components) == 2 and components[1] == ''
Guido van Rossumc629d341992-11-05 10:43:02 +000096
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000097def islink(s):
Jack Jansen992d58b2002-04-22 13:55:43 +000098 """Return true if the pathname refers to a symbolic link."""
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000099
Jack Jansen992d58b2002-04-22 13:55:43 +0000100 try:
Jack Jansen98fc6832003-02-27 23:18:46 +0000101 import Carbon.File
102 return Carbon.File.ResolveAliasFile(s, 0)[2]
Jack Jansen992d58b2002-04-22 13:55:43 +0000103 except:
104 return False
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000105
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000106# Is `stat`/`lstat` a meaningful difference on the Mac? This is safe in any
107# case.
108
109def lexists(path):
110 """Test whether a path exists. Returns True for broken symbolic links"""
111
112 try:
113 st = os.lstat(path)
114 except os.error:
115 return False
116 return True
117
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000118def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000119 """Dummy to retain interface-compatibility with other operating systems."""
120 return path
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000121
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000122
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000123def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000124 """Dummy to retain interface-compatibility with other operating systems."""
125 return path
Guido van Rossum0ec31261995-08-10 18:09:16 +0000126
Neal Norwitz93cf79f2002-03-31 14:06:41 +0000127class norm_error(Exception):
128 """Path cannot be normalized"""
Guido van Rossumc629d341992-11-05 10:43:02 +0000129
130def normpath(s):
Jack Jansen2fc01092000-08-06 21:18:35 +0000131 """Normalize a pathname. Will return the same result for
132 equivalent paths."""
Jack Jansena68bfe21995-08-07 14:09:27 +0000133
Jack Jansen2fc01092000-08-06 21:18:35 +0000134 if ":" not in s:
135 return ":"+s
136
Fred Drakeb4e460a2000-09-28 16:25:20 +0000137 comps = s.split(":")
Jack Jansen2fc01092000-08-06 21:18:35 +0000138 i = 1
139 while i < len(comps)-1:
140 if comps[i] == "" and comps[i-1] != "":
141 if i > 1:
142 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000143 i = i - 1
Jack Jansen2fc01092000-08-06 21:18:35 +0000144 else:
145 # best way to handle this is to raise an exception
Greg Ward034cbf12001-08-08 20:55:10 +0000146 raise norm_error, 'Cannot use :: immediately after volume name'
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000147 else:
Jack Jansen2fc01092000-08-06 21:18:35 +0000148 i = i + 1
149
Fred Drakeb4e460a2000-09-28 16:25:20 +0000150 s = ":".join(comps)
Jack Jansen2fc01092000-08-06 21:18:35 +0000151
152 # remove trailing ":" except for ":" and "Volume:"
153 if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
154 s = s[:-1]
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000155 return s
Guido van Rossum0ec31261995-08-10 18:09:16 +0000156
Jack Jansena68bfe21995-08-07 14:09:27 +0000157
158def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000159 """Directory tree walk with callback function.
160
161 For each directory in the directory tree rooted at top (including top
162 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
163 dirname is the name of the directory, and fnames a list of the names of
164 the files and subdirectories in dirname (excluding '.' and '..'). func
165 may modify the fnames list in-place (e.g. via del or slice assignment),
166 and walk will only recurse into the subdirectories whose names remain in
167 fnames; this can be used to implement a filter, or to impose a specific
168 order of visiting. No semantics are defined for, or required of, arg,
169 beyond that arg is always passed to func. It can be used, e.g., to pass
170 a filename pattern, or a mutable object designed to accumulate
171 statistics. Passing None for arg is common."""
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000172
173 try:
174 names = os.listdir(top)
175 except os.error:
176 return
177 func(arg, top, names)
178 for name in names:
179 name = join(top, name)
Jack Jansen992d58b2002-04-22 13:55:43 +0000180 if isdir(name) and not islink(name):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000181 walk(name, func, arg)
Guido van Rossume294cf61999-01-29 18:05:18 +0000182
183
Guido van Rossume294cf61999-01-29 18:05:18 +0000184def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000185 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000186 if not isabs(path):
187 path = join(os.getcwd(), path)
188 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000189
190# realpath is a no-op on systems without islink support
Jack Jansen992d58b2002-04-22 13:55:43 +0000191def realpath(path):
Tim Peters8ac14952002-05-23 15:15:30 +0000192 path = abspath(path)
193 try:
Jack Jansen98fc6832003-02-27 23:18:46 +0000194 import Carbon.File
Tim Peters8ac14952002-05-23 15:15:30 +0000195 except ImportError:
196 return path
197 if not path:
198 return path
199 components = path.split(':')
200 path = components[0] + ':'
201 for c in components[1:]:
202 path = join(path, c)
Jack Jansen98fc6832003-02-27 23:18:46 +0000203 path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname()
Tim Peters8ac14952002-05-23 15:15:30 +0000204 return path
Mark Hammond8696ebc2002-10-08 02:44:31 +0000205
206supports_unicode_filenames = False