1 """Common operations on Posix pathnames.
2
3 Instead of importing this module directly, import os and refer to
4 this module as os.path. The "os.path" name is an alias for this
5 module on Posix systems; on other systems (e.g. Mac, Windows),
6 os.path provides the same operations in a manner specific to that
7 platform, and is an alias to another module (e.g. macpath, ntpath).
8
9 Some of this can actually be useful on non-Posix systems too, e.g.
10 for manipulation of the pathname component of URLs.
11 """
12
13 import os
14 import sys
15 import stat
16 import genericpath
17 import warnings
18 from genericpath import *
19
20 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
21 "basename","dirname","commonprefix","getsize","getmtime",
22 "getatime","getctime","islink","exists","lexists","isdir","isfile",
23 "ismount","walk","expanduser","expandvars","normpath","abspath",
24 "samefile","sameopenfile","samestat",
25 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
26 "devnull","realpath","supports_unicode_filenames","relpath"]
27
28
29 curdir = '.'
30 pardir = '..'
31 extsep = '.'
32 sep = '/'
33 pathsep = ':'
34 defpath = ':/bin:/usr/bin'
35 altsep = None
36 devnull = '/dev/null'
37
38
39
40
41
42
44 """Normalize case of pathname. Has no effect under Posix"""
45 return s
46
47
48
49
50
52 """Test whether a path is absolute"""
53 return s.startswith('/')
54
55
56
57
58
59
61 """Join two or more pathname components, inserting '/' as needed.
62 If any component is an absolute path, all previous path components
63 will be discarded."""
64 path = a
65 for b in p:
66 if b.startswith('/'):
67 path = b
68 elif path == '' or path.endswith('/'):
69 path += b
70 else:
71 path += '/' + b
72 return path
73
74
75
76
77
78
79
81 """Split a pathname. Returns tuple "(head, tail)" where "tail" is
82 everything after the final slash. Either part may be empty."""
83 i = p.rfind('/') + 1
84 head, tail = p[:i], p[i:]
85 if head and head != '/'*len(head):
86 head = head.rstrip('/')
87 return head, tail
88
89
90
91
92
93
94
96 return genericpath._splitext(p, sep, altsep, extsep)
97 splitext.__doc__ = genericpath._splitext.__doc__
98
99
100
101
103 """Split a pathname into drive and path. On Posix, drive is always
104 empty."""
105 return '', p
106
107
108
109
111 """Returns the final component of a pathname"""
112 i = p.rfind('/') + 1
113 return p[i:]
114
115
116
117
119 """Returns the directory component of a pathname"""
120 i = p.rfind('/') + 1
121 head = p[:i]
122 if head and head != '/'*len(head):
123 head = head.rstrip('/')
124 return head
125
126
127
128
129
131 """Test whether a path is a symbolic link"""
132 try:
133 st = os.lstat(path)
134 except (os.error, AttributeError):
135 return False
136 return stat.S_ISLNK(st.st_mode)
137
138
139
141 """Test whether a path exists. Returns True for broken symbolic links"""
142 try:
143 os.lstat(path)
144 except os.error:
145 return False
146 return True
147
148
149
150
152 """Test whether two pathnames reference the same actual file"""
153 s1 = os.stat(f1)
154 s2 = os.stat(f2)
155 return samestat(s1, s2)
156
157
158
159
160
162 """Test whether two open file objects reference the same file"""
163 s1 = os.fstat(fp1)
164 s2 = os.fstat(fp2)
165 return samestat(s1, s2)
166
167
168
169
170
172 """Test whether two stat buffers reference the same file"""
173 return s1.st_ino == s2.st_ino and \
174 s1.st_dev == s2.st_dev
175
176
177
178
179
181 """Test whether a path is a mount point"""
182 if islink(path):
183
184 return False
185 try:
186 s1 = os.lstat(path)
187 s2 = os.lstat(join(path, '..'))
188 except os.error:
189 return False
190 dev1 = s1.st_dev
191 dev2 = s2.st_dev
192 if dev1 != dev2:
193 return True
194 ino1 = s1.st_ino
195 ino2 = s2.st_ino
196 if ino1 == ino2:
197 return True
198 return False
199
200
201
202
203
204
205
206
207
208
209 -def walk(top, func, arg):
210 """Directory tree walk with callback function.
211
212 For each directory in the directory tree rooted at top (including top
213 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
214 dirname is the name of the directory, and fnames a list of the names of
215 the files and subdirectories in dirname (excluding '.' and '..'). func
216 may modify the fnames list in-place (e.g. via del or slice assignment),
217 and walk will only recurse into the subdirectories whose names remain in
218 fnames; this can be used to implement a filter, or to impose a specific
219 order of visiting. No semantics are defined for, or required of, arg,
220 beyond that arg is always passed to func. It can be used, e.g., to pass
221 a filename pattern, or a mutable object designed to accumulate
222 statistics. Passing None for arg is common."""
223 warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",
224 stacklevel=2)
225 try:
226 names = os.listdir(top)
227 except os.error:
228 return
229 func(arg, top, names)
230 for name in names:
231 name = join(top, name)
232 try:
233 st = os.lstat(name)
234 except os.error:
235 continue
236 if stat.S_ISDIR(st.st_mode):
237 walk(name, func, arg)
238
239
240
241
242
243
244
245
246
247
248
250 """Expand ~ and ~user constructions. If user or $HOME is unknown,
251 do nothing."""
252 if not path.startswith('~'):
253 return path
254 i = path.find('/', 1)
255 if i < 0:
256 i = len(path)
257 if i == 1:
258 if 'HOME' not in os.environ:
259 import pwd
260 userhome = pwd.getpwuid(os.getuid()).pw_dir
261 else:
262 userhome = os.environ['HOME']
263 else:
264 import pwd
265 try:
266 pwent = pwd.getpwnam(path[1:i])
267 except KeyError:
268 return path
269 userhome = pwent.pw_dir
270 userhome = userhome.rstrip('/') or userhome
271 return userhome + path[i:]
272
273
274
275
276
277
278 _varprog = None
279
306
307
308
309
310
311
313 """Normalize path, eliminating double slashes, etc."""
314
315 slash, dot = (u'/', u'.') if isinstance(path, unicode) else ('/', '.')
316 if path == '':
317 return dot
318 initial_slashes = path.startswith('/')
319
320
321 if (initial_slashes and
322 path.startswith('//') and not path.startswith('///')):
323 initial_slashes = 2
324 comps = path.split('/')
325 new_comps = []
326 for comp in comps:
327 if comp in ('', '.'):
328 continue
329 if (comp != '..' or (not initial_slashes and not new_comps) or
330 (new_comps and new_comps[-1] == '..')):
331 new_comps.append(comp)
332 elif new_comps:
333 new_comps.pop()
334 comps = new_comps
335 path = slash.join(comps)
336 if initial_slashes:
337 path = slash*initial_slashes + path
338 return path or dot
339
340
342 """Return an absolute path."""
343 if not isabs(path):
344 if isinstance(path, unicode):
345 cwd = os.getcwdu()
346 else:
347 cwd = os.getcwd()
348 path = join(cwd, path)
349 return normpath(path)
350
351
352
353
354
356 """Return the canonical path of the specified filename, eliminating any
357 symbolic links encountered in the path."""
358 if isabs(filename):
359 bits = ['/'] + filename.split('/')[1:]
360 else:
361 bits = [''] + filename.split('/')
362
363 for i in range(2, len(bits)+1):
364 component = join(*bits[0:i])
365
366 if islink(component):
367 resolved = _resolve_link(component)
368 if resolved is None:
369
370 return abspath(join(*([component] + bits[i:])))
371 else:
372 newpath = join(*([resolved] + bits[i:]))
373 return realpath(newpath)
374
375 return abspath(filename)
376
377
379 """Internal helper function. Takes a path and follows symlinks
380 until we either arrive at something that isn't a symlink, or
381 encounter a path we've seen before (meaning that there's a loop).
382 """
383 paths_seen = set()
384 while islink(path):
385 if path in paths_seen:
386
387 return None
388 paths_seen.add(path)
389
390 resolved = os.readlink(path)
391 if not isabs(resolved):
392 dir = dirname(path)
393 path = normpath(join(dir, resolved))
394 else:
395 path = normpath(resolved)
396 return path
397
398 supports_unicode_filenames = (sys.platform == 'darwin')
399
401 """Return a relative version of a path"""
402
403 if not path:
404 raise ValueError("no path specified")
405
406 start_list = [x for x in abspath(start).split(sep) if x]
407 path_list = [x for x in abspath(path).split(sep) if x]
408
409
410 i = len(commonprefix([start_list, path_list]))
411
412 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
413 if not rel_list:
414 return curdir
415 return join(*rel_list)
416