Merged revisions 78818 via svnmerge from
[python/dscho.git] / Lib / macpath.py
blobc02364624436ab84c7d8ca267ea5425043671408
1 """Pathname and path-related operations for the Macintosh."""
3 import os
4 from stat import *
5 import genericpath
6 from genericpath import *
8 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
9 "basename","dirname","commonprefix","getsize","getmtime",
10 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
11 "expanduser","expandvars","normpath","abspath",
12 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
13 "devnull","realpath","supports_unicode_filenames"]
15 # strings representing various path-related bits and pieces
16 # These are primarily for export; internally, they are hardcoded.
17 curdir = ':'
18 pardir = '::'
19 extsep = '.'
20 sep = ':'
21 pathsep = '\n'
22 defpath = ':'
23 altsep = None
24 devnull = 'Dev:Null'
26 def _get_colon(path):
27 if isinstance(path, bytes):
28 return b':'
29 else:
30 return ':'
32 # Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
34 def normcase(path):
35 return path.lower()
38 def isabs(s):
39 """Return true if a path is absolute.
40 On the Mac, relative paths begin with a colon,
41 but as a special case, paths with no colons at all are also relative.
42 Anything else is absolute (the string up to the first colon is the
43 volume name)."""
45 colon = _get_colon(s)
46 return colon in s and s[:1] != colon
49 def join(s, *p):
50 colon = _get_colon(s)
51 path = s
52 for t in p:
53 if (not s) or isabs(t):
54 path = t
55 continue
56 if t[:1] == colon:
57 t = t[1:]
58 if colon not in path:
59 path = colon + path
60 if path[-1:] != colon:
61 path = path + colon
62 path = path + t
63 return path
66 def split(s):
67 """Split a pathname into two parts: the directory leading up to the final
68 bit, and the basename (the filename, without colons, in that directory).
69 The result (s, t) is such that join(s, t) yields the original argument."""
71 colon = _get_colon(s)
72 if colon not in s: return s[:0], s
73 col = 0
74 for i in range(len(s)):
75 if s[i:i+1] == colon: col = i + 1
76 path, file = s[:col-1], s[col:]
77 if path and not colon in path:
78 path = path + colon
79 return path, file
82 def splitext(p):
83 if isinstance(p, bytes):
84 return genericpath._splitext(p, b':', altsep, b'.')
85 else:
86 return genericpath._splitext(p, sep, altsep, extsep)
87 splitext.__doc__ = genericpath._splitext.__doc__
89 def splitdrive(p):
90 """Split a pathname into a drive specification and the rest of the
91 path. Useful on DOS/Windows/NT; on the Mac, the drive is always
92 empty (don't use the volume name -- it doesn't have the same
93 syntactic and semantic oddities as DOS drive letters, such as there
94 being a separate current directory per drive)."""
96 return p[:0], p
99 # Short interfaces to split()
101 def dirname(s): return split(s)[0]
102 def basename(s): return split(s)[1]
104 def ismount(s):
105 if not isabs(s):
106 return False
107 components = split(s)
108 return len(components) == 2 and not components[1]
110 def islink(s):
111 """Return true if the pathname refers to a symbolic link."""
113 try:
114 import Carbon.File
115 return Carbon.File.ResolveAliasFile(s, 0)[2]
116 except:
117 return False
119 # Is `stat`/`lstat` a meaningful difference on the Mac? This is safe in any
120 # case.
122 def lexists(path):
123 """Test whether a path exists. Returns True for broken symbolic links"""
125 try:
126 st = os.lstat(path)
127 except os.error:
128 return False
129 return True
131 def expandvars(path):
132 """Dummy to retain interface-compatibility with other operating systems."""
133 return path
136 def expanduser(path):
137 """Dummy to retain interface-compatibility with other operating systems."""
138 return path
140 class norm_error(Exception):
141 """Path cannot be normalized"""
143 def normpath(s):
144 """Normalize a pathname. Will return the same result for
145 equivalent paths."""
147 colon = _get_colon(s)
149 if colon not in s:
150 return colon + s
152 comps = s.split(colon)
153 i = 1
154 while i < len(comps)-1:
155 if not comps[i] and comps[i-1]:
156 if i > 1:
157 del comps[i-1:i+1]
158 i = i - 1
159 else:
160 # best way to handle this is to raise an exception
161 raise norm_error('Cannot use :: immediately after volume name')
162 else:
163 i = i + 1
165 s = colon.join(comps)
167 # remove trailing ":" except for ":" and "Volume:"
168 if s[-1:] == colon and len(comps) > 2 and s != colon*len(s):
169 s = s[:-1]
170 return s
172 def abspath(path):
173 """Return an absolute path."""
174 if not isabs(path):
175 path = join(os.getcwd(), path)
176 return normpath(path)
178 # realpath is a no-op on systems without islink support
179 def realpath(path):
180 path = abspath(path)
181 try:
182 import Carbon.File
183 except ImportError:
184 return path
185 if not path:
186 return path
187 colon = _get_colon(path)
188 components = path.split(colon)
189 path = components[0] + colon
190 for c in components[1:]:
191 path = join(path, c)
192 path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname()
193 return path
195 supports_unicode_filenames = False