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 from genericpath import _unicode
20
21 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
22 "basename","dirname","commonprefix","getsize","getmtime",
23 "getatime","getctime","islink","exists","lexists","isdir","isfile",
24 "ismount","walk","expanduser","expandvars","normpath","abspath",
25 "samefile","sameopenfile","samestat",
26 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
27 "devnull","realpath","supports_unicode_filenames","relpath"]
28
29
30 curdir = '.'
31 pardir = '..'
32 extsep = '.'
33 sep = '/'
34 pathsep = ':'
35 defpath = ':/bin:/usr/bin'
36 altsep = None
37 devnull = '/dev/null'
38
39
40
41
42
43
45 """Normalize case of pathname. Has no effect under Posix"""
46 return s
47
48
49
50
51
53 """Test whether a path is absolute"""
54 return s.startswith('/')
55
56
57
58
59
60
62 """Join two or more pathname components, inserting '/' as needed.
63 If any component is an absolute path, all previous path components
64 will be discarded. An empty last part will result in a path that
65 ends with a separator."""
66 path = a
67 for b in p:
68 if b.startswith('/'):
69 path = b
70 elif path == '' or path.endswith('/'):
71 path += b
72 else:
73 path += '/' + b
74 return path
75
76
77
78
79
80
81
83 """Split a pathname. Returns tuple "(head, tail)" where "tail" is
84 everything after the final slash. Either part may be empty."""
85 i = p.rfind('/') + 1
86 head, tail = p[:i], p[i:]
87 if head and head != '/'*len(head):
88 head = head.rstrip('/')
89 return head, tail
90
91
92
93
94
95
96
98 return genericpath._splitext(p, sep, altsep, extsep)
99 splitext.__doc__ = genericpath._splitext.__doc__
100
101
102
103
105 """Split a pathname into drive and path. On Posix, drive is always
106 empty."""
107 return '', p
108
109
110
111
113 """Returns the final component of a pathname"""
114 i = p.rfind('/') + 1
115 return p[i:]
116
117
118
119
121 """Returns the directory component of a pathname"""
122 i = p.rfind('/') + 1
123 head = p[:i]
124 if head and head != '/'*len(head):
125 head = head.rstrip('/')
126 return head
127
128
129
130
131
133 """Test whether a path is a symbolic link"""
134 try:
135 st = os.lstat(path)
136 except (os.error, AttributeError):
137 return False
138 return stat.S_ISLNK(st.st_mode)
139
140
141
143 """Test whether a path exists. Returns True for broken symbolic links"""
144 try:
145 os.lstat(path)
146 except os.error:
147 return False
148 return True
149
150
151
152
154 """Test whether two pathnames reference the same actual file"""
155 s1 = os.stat(f1)
156 s2 = os.stat(f2)
157 return samestat(s1, s2)
158
159
160
161
162
164 """Test whether two open file objects reference the same file"""
165 s1 = os.fstat(fp1)
166 s2 = os.fstat(fp2)
167 return samestat(s1, s2)
168
169
170
171
172
174 """Test whether two stat buffers reference the same file"""
175 return s1.st_ino == s2.st_ino and \
176 s1.st_dev == s2.st_dev
177
178
179
180
181
183 """Test whether a path is a mount point"""
184 if islink(path):
185
186 return False
187 try:
188 s1 = os.lstat(path)
189 s2 = os.lstat(realpath(join(path, '..')))
190 except os.error:
191 return False
192 dev1 = s1.st_dev
193 dev2 = s2.st_dev
194 if dev1 != dev2:
195 return True
196 ino1 = s1.st_ino
197 ino2 = s2.st_ino
198 if ino1 == ino2:
199 return True
200 return False
201
202
203
204
205
206
207
208
209
210
211 -def walk(top, func, arg):
212 """Directory tree walk with callback function.
213
214 For each directory in the directory tree rooted at top (including top
215 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
216 dirname is the name of the directory, and fnames a list of the names of
217 the files and subdirectories in dirname (excluding '.' and '..'). func
218 may modify the fnames list in-place (e.g. via del or slice assignment),
219 and walk will only recurse into the subdirectories whose names remain in
220 fnames; this can be used to implement a filter, or to impose a specific
221 order of visiting. No semantics are defined for, or required of, arg,
222 beyond that arg is always passed to func. It can be used, e.g., to pass
223 a filename pattern, or a mutable object designed to accumulate
224 statistics. Passing None for arg is common."""
225 warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",
226 stacklevel=2)
227 try:
228 names = os.listdir(top)
229 except os.error:
230 return
231 func(arg, top, names)
232 for name in names:
233 name = join(top, name)
234 try:
235 st = os.lstat(name)
236 except os.error:
237 continue
238 if stat.S_ISDIR(st.st_mode):
239 walk(name, func, arg)
240
241
242
243
244
245
246
247
248
249
250
252 """Expand ~ and ~user constructions. If user or $HOME is unknown,
253 do nothing."""
254 if not path.startswith('~'):
255 return path
256 i = path.find('/', 1)
257 if i < 0:
258 i = len(path)
259 if i == 1:
260 if 'HOME' not in os.environ:
261 import pwd
262 try:
263 userhome = pwd.getpwuid(os.getuid()).pw_dir
264 except KeyError:
265
266
267 return path
268 else:
269 userhome = os.environ['HOME']
270 else:
271 import pwd
272 try:
273 pwent = pwd.getpwnam(path[1:i])
274 except KeyError:
275
276
277 return path
278 userhome = pwent.pw_dir
279 userhome = userhome.rstrip('/')
280 return (userhome + path[i:]) or '/'
281
282
283
284
285
286
287 _varprog = None
288 _uvarprog = None
289
330
331
332
333
334
335
337 """Normalize path, eliminating double slashes, etc."""
338
339 slash, dot = (u'/', u'.') if isinstance(path, _unicode) else ('/', '.')
340 if path == '':
341 return dot
342 initial_slashes = path.startswith('/')
343
344
345 if (initial_slashes and
346 path.startswith('//') and not path.startswith('///')):
347 initial_slashes = 2
348 comps = path.split('/')
349 new_comps = []
350 for comp in comps:
351 if comp in ('', '.'):
352 continue
353 if (comp != '..' or (not initial_slashes and not new_comps) or
354 (new_comps and new_comps[-1] == '..')):
355 new_comps.append(comp)
356 elif new_comps:
357 new_comps.pop()
358 comps = new_comps
359 path = slash.join(comps)
360 if initial_slashes:
361 path = slash*initial_slashes + path
362 return path or dot
363
364
366 """Return an absolute path."""
367 if not isabs(path):
368 if isinstance(path, _unicode):
369 cwd = os.getcwdu()
370 else:
371 cwd = os.getcwd()
372 path = join(cwd, path)
373 return normpath(path)
374
375
376
377
378
380 """Return the canonical path of the specified filename, eliminating any
381 symbolic links encountered in the path."""
382 path, ok = _joinrealpath('', filename, {})
383 return abspath(path)
384
385
386
388 if isabs(rest):
389 rest = rest[1:]
390 path = sep
391
392 while rest:
393 name, _, rest = rest.partition(sep)
394 if not name or name == curdir:
395
396 continue
397 if name == pardir:
398
399 if path:
400 path, name = split(path)
401 if name == pardir:
402 path = join(path, pardir, pardir)
403 else:
404 path = pardir
405 continue
406 newpath = join(path, name)
407 if not islink(newpath):
408 path = newpath
409 continue
410
411 if newpath in seen:
412
413 path = seen[newpath]
414 if path is not None:
415
416 continue
417
418
419 return join(newpath, rest), False
420 seen[newpath] = None
421 path, ok = _joinrealpath(path, os.readlink(newpath), seen)
422 if not ok:
423 return join(path, rest), False
424 seen[newpath] = path
425
426 return path, True
427
428
429 supports_unicode_filenames = (sys.platform == 'darwin')
430
432 """Return a relative version of a path"""
433
434 if not path:
435 raise ValueError("no path specified")
436
437 start_list = [x for x in abspath(start).split(sep) if x]
438 path_list = [x for x in abspath(path).split(sep) if x]
439
440
441 i = len(commonprefix([start_list, path_list]))
442
443 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
444 if not rel_list:
445 return curdir
446 return join(*rel_list)
447