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