Catch situations where currentframe() returns None. See SF patch #1447410, this is...
[python.git] / Lib / macpath.py
blobf93ceb154014fd72355ce68f60eda39d91f32a2b
1 """Pathname and path-related operations for the Macintosh."""
3 import os
4 from stat import *
6 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
7 "basename","dirname","commonprefix","getsize","getmtime",
8 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
9 "walk","expanduser","expandvars","normpath","abspath",
10 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
11 "devnull","realpath","supports_unicode_filenames"]
13 # strings representing various path-related bits and pieces
14 curdir = ':'
15 pardir = '::'
16 extsep = '.'
17 sep = ':'
18 pathsep = '\n'
19 defpath = ':'
20 altsep = None
21 devnull = 'Dev:Null'
23 # Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
25 def normcase(path):
26 return path.lower()
29 def isabs(s):
30 """Return true if a path is absolute.
31 On the Mac, relative paths begin with a colon,
32 but as a special case, paths with no colons at all are also relative.
33 Anything else is absolute (the string up to the first colon is the
34 volume name)."""
36 return ':' in s and s[0] != ':'
39 def join(s, *p):
40 path = s
41 for t in p:
42 if (not s) or isabs(t):
43 path = t
44 continue
45 if t[:1] == ':':
46 t = t[1:]
47 if ':' not in path:
48 path = ':' + path
49 if path[-1:] != ':':
50 path = path + ':'
51 path = path + t
52 return path
55 def split(s):
56 """Split a pathname into two parts: the directory leading up to the final
57 bit, and the basename (the filename, without colons, in that directory).
58 The result (s, t) is such that join(s, t) yields the original argument."""
60 if ':' not in s: return '', s
61 colon = 0
62 for i in range(len(s)):
63 if s[i] == ':': colon = i + 1
64 path, file = s[:colon-1], s[colon:]
65 if path and not ':' in path:
66 path = path + ':'
67 return path, file
70 def splitext(p):
71 """Split a path into root and extension.
72 The extension is everything starting at the last dot in the last
73 pathname component; the root is everything before that.
74 It is always true that root + ext == p."""
76 i = p.rfind('.')
77 if i<=p.rfind(':'):
78 return p, ''
79 else:
80 return p[:i], p[i:]
83 def splitdrive(p):
84 """Split a pathname into a drive specification and the rest of the
85 path. Useful on DOS/Windows/NT; on the Mac, the drive is always
86 empty (don't use the volume name -- it doesn't have the same
87 syntactic and semantic oddities as DOS drive letters, such as there
88 being a separate current directory per drive)."""
90 return '', p
93 # Short interfaces to split()
95 def dirname(s): return split(s)[0]
96 def basename(s): return split(s)[1]
98 def ismount(s):
99 if not isabs(s):
100 return False
101 components = split(s)
102 return len(components) == 2 and components[1] == ''
104 def isdir(s):
105 """Return true if the pathname refers to an existing directory."""
107 try:
108 st = os.stat(s)
109 except os.error:
110 return 0
111 return S_ISDIR(st.st_mode)
114 # Get size, mtime, atime of files.
116 def getsize(filename):
117 """Return the size of a file, reported by os.stat()."""
118 return os.stat(filename).st_size
120 def getmtime(filename):
121 """Return the last modification time of a file, reported by os.stat()."""
122 return os.stat(filename).st_mtime
124 def getatime(filename):
125 """Return the last access time of a file, reported by os.stat()."""
126 return os.stat(filename).st_atime
129 def islink(s):
130 """Return true if the pathname refers to a symbolic link."""
132 try:
133 import Carbon.File
134 return Carbon.File.ResolveAliasFile(s, 0)[2]
135 except:
136 return False
139 def isfile(s):
140 """Return true if the pathname refers to an existing regular file."""
142 try:
143 st = os.stat(s)
144 except os.error:
145 return False
146 return S_ISREG(st.st_mode)
148 def getctime(filename):
149 """Return the creation time of a file, reported by os.stat()."""
150 return os.stat(filename).st_ctime
152 def exists(s):
153 """Test whether a path exists. Returns False for broken symbolic links"""
155 try:
156 st = os.stat(s)
157 except os.error:
158 return False
159 return True
161 # Is `stat`/`lstat` a meaningful difference on the Mac? This is safe in any
162 # case.
164 def lexists(path):
165 """Test whether a path exists. Returns True for broken symbolic links"""
167 try:
168 st = os.lstat(path)
169 except os.error:
170 return False
171 return True
173 # Return the longest prefix of all list elements.
175 def commonprefix(m):
176 "Given a list of pathnames, returns the longest common leading component"
177 if not m: return ''
178 s1 = min(m)
179 s2 = max(m)
180 n = min(len(s1), len(s2))
181 for i in xrange(n):
182 if s1[i] != s2[i]:
183 return s1[:i]
184 return s1[:n]
187 def expandvars(path):
188 """Dummy to retain interface-compatibility with other operating systems."""
189 return path
192 def expanduser(path):
193 """Dummy to retain interface-compatibility with other operating systems."""
194 return path
196 class norm_error(Exception):
197 """Path cannot be normalized"""
199 def normpath(s):
200 """Normalize a pathname. Will return the same result for
201 equivalent paths."""
203 if ":" not in s:
204 return ":"+s
206 comps = s.split(":")
207 i = 1
208 while i < len(comps)-1:
209 if comps[i] == "" and comps[i-1] != "":
210 if i > 1:
211 del comps[i-1:i+1]
212 i = i - 1
213 else:
214 # best way to handle this is to raise an exception
215 raise norm_error, 'Cannot use :: immediately after volume name'
216 else:
217 i = i + 1
219 s = ":".join(comps)
221 # remove trailing ":" except for ":" and "Volume:"
222 if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
223 s = s[:-1]
224 return s
227 def walk(top, func, arg):
228 """Directory tree walk with callback function.
230 For each directory in the directory tree rooted at top (including top
231 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
232 dirname is the name of the directory, and fnames a list of the names of
233 the files and subdirectories in dirname (excluding '.' and '..'). func
234 may modify the fnames list in-place (e.g. via del or slice assignment),
235 and walk will only recurse into the subdirectories whose names remain in
236 fnames; this can be used to implement a filter, or to impose a specific
237 order of visiting. No semantics are defined for, or required of, arg,
238 beyond that arg is always passed to func. It can be used, e.g., to pass
239 a filename pattern, or a mutable object designed to accumulate
240 statistics. Passing None for arg is common."""
242 try:
243 names = os.listdir(top)
244 except os.error:
245 return
246 func(arg, top, names)
247 for name in names:
248 name = join(top, name)
249 if isdir(name) and not islink(name):
250 walk(name, func, arg)
253 def abspath(path):
254 """Return an absolute path."""
255 if not isabs(path):
256 path = join(os.getcwd(), path)
257 return normpath(path)
259 # realpath is a no-op on systems without islink support
260 def realpath(path):
261 path = abspath(path)
262 try:
263 import Carbon.File
264 except ImportError:
265 return path
266 if not path:
267 return path
268 components = path.split(':')
269 path = components[0] + ':'
270 for c in components[1:]:
271 path = join(path, c)
272 path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname()
273 return path
275 supports_unicode_filenames = False