Update version number and release date.
[python/dscho.git] / Lib / macpath.py
blob695fac913289d77fe93aa9bb43b88e63fc776cd9
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","isdir","isfile",
9 "walk","expanduser","expandvars","normpath","abspath",
10 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
11 "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
22 # Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
24 def normcase(path):
25 return path.lower()
28 def isabs(s):
29 """Return true if a path is absolute.
30 On the Mac, relative paths begin with a colon,
31 but as a special case, paths with no colons at all are also relative.
32 Anything else is absolute (the string up to the first colon is the
33 volume name)."""
35 return ':' in s and s[0] != ':'
38 def join(s, *p):
39 path = s
40 for t in p:
41 if (not s) or isabs(t):
42 path = t
43 continue
44 if t[:1] == ':':
45 t = t[1:]
46 if ':' not in path:
47 path = ':' + path
48 if path[-1:] != ':':
49 path = path + ':'
50 path = path + t
51 return path
54 def split(s):
55 """Split a pathname into two parts: the directory leading up to the final
56 bit, and the basename (the filename, without colons, in that directory).
57 The result (s, t) is such that join(s, t) yields the original argument."""
59 if ':' not in s: return '', s
60 colon = 0
61 for i in range(len(s)):
62 if s[i] == ':': colon = i + 1
63 path, file = s[:colon-1], s[colon:]
64 if path and not ':' in path:
65 path = path + ':'
66 return path, file
69 def splitext(p):
70 """Split a path into root and extension.
71 The extension is everything starting at the last dot in the last
72 pathname component; the root is everything before that.
73 It is always true that root + ext == p."""
75 i = p.rfind('.')
76 if i<=p.rfind(':'):
77 return p, ''
78 else:
79 return p[:i], p[i:]
82 def splitdrive(p):
83 """Split a pathname into a drive specification and the rest of the
84 path. Useful on DOS/Windows/NT; on the Mac, the drive is always
85 empty (don't use the volume name -- it doesn't have the same
86 syntactic and semantic oddities as DOS drive letters, such as there
87 being a separate current directory per drive)."""
89 return '', p
92 # Short interfaces to split()
94 def dirname(s): return split(s)[0]
95 def basename(s): return split(s)[1]
97 def ismount(s):
98 if not isabs(s):
99 return False
100 components = split(s)
101 return len(components) == 2 and components[1] == ''
103 def isdir(s):
104 """Return true if the pathname refers to an existing directory."""
106 try:
107 st = os.stat(s)
108 except os.error:
109 return 0
110 return S_ISDIR(st.st_mode)
113 # Get size, mtime, atime of files.
115 def getsize(filename):
116 """Return the size of a file, reported by os.stat()."""
117 return os.stat(filename).st_size
119 def getmtime(filename):
120 """Return the last modification time of a file, reported by os.stat()."""
121 return os.stat(filename).st_mtime
123 def getatime(filename):
124 """Return the last access time of a file, reported by os.stat()."""
125 return os.stat(filename).st_atime
128 def islink(s):
129 """Return true if the pathname refers to a symbolic link."""
131 try:
132 import Carbon.File
133 return Carbon.File.ResolveAliasFile(s, 0)[2]
134 except:
135 return False
138 def isfile(s):
139 """Return true if the pathname refers to an existing regular file."""
141 try:
142 st = os.stat(s)
143 except os.error:
144 return False
145 return S_ISREG(st.st_mode)
147 def getctime(filename):
148 """Return the creation time of a file, reported by os.stat()."""
149 return os.stat(filename).st_ctime
151 def exists(s):
152 """Return True if the pathname refers to an existing file or directory."""
154 try:
155 st = os.stat(s)
156 except os.error:
157 return False
158 return True
160 # Return the longest prefix of all list elements.
162 def commonprefix(m):
163 "Given a list of pathnames, returns the longest common leading component"
164 if not m: return ''
165 prefix = m[0]
166 for item in m:
167 for i in range(len(prefix)):
168 if prefix[:i+1] != item[:i+1]:
169 prefix = prefix[:i]
170 if i == 0: return ''
171 break
172 return prefix
174 def expandvars(path):
175 """Dummy to retain interface-compatibility with other operating systems."""
176 return path
179 def expanduser(path):
180 """Dummy to retain interface-compatibility with other operating systems."""
181 return path
183 class norm_error(Exception):
184 """Path cannot be normalized"""
186 def normpath(s):
187 """Normalize a pathname. Will return the same result for
188 equivalent paths."""
190 if ":" not in s:
191 return ":"+s
193 comps = s.split(":")
194 i = 1
195 while i < len(comps)-1:
196 if comps[i] == "" and comps[i-1] != "":
197 if i > 1:
198 del comps[i-1:i+1]
199 i = i - 1
200 else:
201 # best way to handle this is to raise an exception
202 raise norm_error, 'Cannot use :: immediately after volume name'
203 else:
204 i = i + 1
206 s = ":".join(comps)
208 # remove trailing ":" except for ":" and "Volume:"
209 if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
210 s = s[:-1]
211 return s
214 def walk(top, func, arg):
215 """Directory tree walk with callback function.
217 For each directory in the directory tree rooted at top (including top
218 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
219 dirname is the name of the directory, and fnames a list of the names of
220 the files and subdirectories in dirname (excluding '.' and '..'). func
221 may modify the fnames list in-place (e.g. via del or slice assignment),
222 and walk will only recurse into the subdirectories whose names remain in
223 fnames; this can be used to implement a filter, or to impose a specific
224 order of visiting. No semantics are defined for, or required of, arg,
225 beyond that arg is always passed to func. It can be used, e.g., to pass
226 a filename pattern, or a mutable object designed to accumulate
227 statistics. Passing None for arg is common."""
229 try:
230 names = os.listdir(top)
231 except os.error:
232 return
233 func(arg, top, names)
234 for name in names:
235 name = join(top, name)
236 if isdir(name) and not islink(name):
237 walk(name, func, arg)
240 def abspath(path):
241 """Return an absolute path."""
242 if not isabs(path):
243 path = join(os.getcwd(), path)
244 return normpath(path)
246 # realpath is a no-op on systems without islink support
247 def realpath(path):
248 path = abspath(path)
249 try:
250 import Carbon.File
251 except ImportError:
252 return path
253 if not path:
254 return path
255 components = path.split(':')
256 path = components[0] + ':'
257 for c in components[1:]:
258 path = join(path, c)
259 path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname()
260 return path
262 supports_unicode_filenames = False