1
2 """Common pathname manipulations, WindowsNT/95 version.
3
4 Instead of importing this module directly, import os and refer to this
5 module as os.path.
6 """
7
8 import os
9 import stat
10 import sys
11
12 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
13 "basename","dirname","commonprefix","getsize","getmtime",
14 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
15 "ismount","walk","expanduser","expandvars","normpath","abspath",
16 "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
17 "extsep","devnull","realpath","supports_unicode_filenames"]
18
19
20 curdir = '.'
21 pardir = '..'
22 extsep = '.'
23 sep = '\\'
24 pathsep = ';'
25 altsep = '/'
26 defpath = '.;C:\\bin'
27 if 'ce' in sys.builtin_module_names:
28 defpath = '\\Windows'
29 elif 'os2' in sys.builtin_module_names:
30
31 altsep = '/'
32 devnull = 'nul'
33
34
35
36
37
39 """Normalize case of pathname.
40
41 Makes all characters lowercase and all slashes into backslashes."""
42 return s.replace("/", "\\").lower()
43
44
45
46
47
48
49
50
52 """Test whether a path is absolute"""
53 s = splitdrive(s)[1]
54 return s != '' and s[:1] in '/\\'
55
56
57
58
60 """Join two or more pathname components, inserting "\\" as needed"""
61 path = a
62 for b in p:
63 b_wins = 0
64 if path == "":
65 b_wins = 1
66
67 elif isabs(b):
68
69
70
71
72
73
74
75
76 if path[1:2] != ":" or b[1:2] == ":":
77
78 b_wins = 1
79
80
81 elif len(path) > 3 or (len(path) == 3 and
82 path[-1] not in "/\\"):
83
84 b_wins = 1
85
86 if b_wins:
87 path = b
88 else:
89
90 assert len(path) > 0
91 if path[-1] in "/\\":
92 if b and b[0] in "/\\":
93 path += b[1:]
94 else:
95 path += b
96 elif path[-1] == ":":
97 path += b
98 elif b:
99 if b[0] in "/\\":
100 path += b
101 else:
102 path += "\\" + b
103 else:
104
105
106
107
108 path += '\\'
109
110 return path
111
112
113
114
115
117 """Split a pathname into drive and path specifiers. Returns a 2-tuple
118 "(drive,path)"; either part may be empty"""
119 if p[1:2] == ':':
120 return p[0:2], p[2:]
121 return '', p
122
123
124
126 """Split a pathname into UNC mount point and relative path specifiers.
127
128 Return a 2-tuple (unc, rest); either part may be empty.
129 If unc is not empty, it has the form '//host/mount' (or similar
130 using backslashes). unc+rest is always the input path.
131 Paths containing drive letters never have an UNC part.
132 """
133 if p[1:2] == ':':
134 return '', p
135 firstTwo = p[0:2]
136 if firstTwo == '//' or firstTwo == '\\\\':
137
138
139
140
141 normp = normcase(p)
142 index = normp.find('\\', 2)
143 if index == -1:
144
145 return ("", p)
146 index = normp.find('\\', index + 1)
147 if index == -1:
148 index = len(p)
149 return p[:index], p[index:]
150 return '', p
151
152
153
154
155
156
157
159 """Split a pathname.
160
161 Return tuple (head, tail) where tail is everything after the final slash.
162 Either part may be empty."""
163
164 d, p = splitdrive(p)
165
166 i = len(p)
167 while i and p[i-1] not in '/\\':
168 i = i - 1
169 head, tail = p[:i], p[i:]
170
171 head2 = head
172 while head2 and head2[-1] in '/\\':
173 head2 = head2[:-1]
174 head = head2 or head
175 return d + head, tail
176
177
178
179
180
181
182
184 """Split the extension from a pathname.
185
186 Extension is everything from the last dot to the end.
187 Return (root, ext), either part may be empty."""
188
189 i = p.rfind('.')
190 if i<=max(p.rfind('/'), p.rfind('\\')):
191 return p, ''
192 else:
193 return p[:i], p[i:]
194
195
196
197
199 """Returns the final component of a pathname"""
200 return split(p)[1]
201
202
203
204
206 """Returns the directory component of a pathname"""
207 return split(p)[0]
208
209
210
211
213 "Given a list of pathnames, returns the longest common leading component"
214 if not m: return ''
215 s1 = min(m)
216 s2 = max(m)
217 n = min(len(s1), len(s2))
218 for i in xrange(n):
219 if s1[i] != s2[i]:
220 return s1[:i]
221 return s1[:n]
222
223
224
225
227 """Return the size of a file, reported by os.stat()"""
228 return os.stat(filename).st_size
229
231 """Return the last modification time of a file, reported by os.stat()"""
232 return os.stat(filename).st_mtime
233
235 """Return the last access time of a file, reported by os.stat()"""
236 return os.stat(filename).st_atime
237
239 """Return the creation time of a file, reported by os.stat()."""
240 return os.stat(filename).st_ctime
241
242
243
244
246 """Test for symbolic link. On WindowsNT/95 always returns false"""
247 return False
248
249
250
251
253 """Test whether a path exists"""
254 try:
255 st = os.stat(path)
256 except os.error:
257 return False
258 return True
259
260 lexists = exists
261
262
263
264
265
266
268 """Test whether a path is a directory"""
269 try:
270 st = os.stat(path)
271 except os.error:
272 return False
273 return stat.S_ISDIR(st.st_mode)
274
275
276
277
278
279
281 """Test whether a path is a regular file"""
282 try:
283 st = os.stat(path)
284 except os.error:
285 return False
286 return stat.S_ISREG(st.st_mode)
287
288
289
290
291
293 """Test whether a path is a mount point (defined as root of drive)"""
294 unc, rest = splitunc(path)
295 if unc:
296 return rest in ("", "/", "\\")
297 p = splitdrive(path)[1]
298 return len(p) == 1 and p[0] in '/\\'
299
300
301
302
303
304
305
306
307
308
309 -def walk(top, func, arg):
310 """Directory tree walk with callback function.
311
312 For each directory in the directory tree rooted at top (including top
313 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
314 dirname is the name of the directory, and fnames a list of the names of
315 the files and subdirectories in dirname (excluding '.' and '..'). func
316 may modify the fnames list in-place (e.g. via del or slice assignment),
317 and walk will only recurse into the subdirectories whose names remain in
318 fnames; this can be used to implement a filter, or to impose a specific
319 order of visiting. No semantics are defined for, or required of, arg,
320 beyond that arg is always passed to func. It can be used, e.g., to pass
321 a filename pattern, or a mutable object designed to accumulate
322 statistics. Passing None for arg is common."""
323
324 try:
325 names = os.listdir(top)
326 except os.error:
327 return
328 func(arg, top, names)
329 exceptions = ('.', '..')
330 for name in names:
331 if name not in exceptions:
332 name = join(top, name)
333 if isdir(name):
334 walk(name, func, arg)
335
336
337
338
339
340
341
342
343
344
345
347 """Expand ~ and ~user constructs.
348
349 If user or $HOME is unknown, do nothing."""
350 if path[:1] != '~':
351 return path
352 i, n = 1, len(path)
353 while i < n and path[i] not in '/\\':
354 i = i + 1
355 if i == 1:
356 if 'HOME' in os.environ:
357 userhome = os.environ['HOME']
358 elif not 'HOMEPATH' in os.environ:
359 return path
360 else:
361 try:
362 drive = os.environ['HOMEDRIVE']
363 except KeyError:
364 drive = ''
365 userhome = join(drive, os.environ['HOMEPATH'])
366 else:
367 return path
368 return userhome + path[i:]
369
370
371
372
373
374
375
376
377
378
379
381 """Expand shell variables of form $var and ${var}.
382
383 Unknown variables are left unchanged."""
384 if '$' not in path:
385 return path
386 import string
387 varchars = string.ascii_letters + string.digits + '_-'
388 res = ''
389 index = 0
390 pathlen = len(path)
391 while index < pathlen:
392 c = path[index]
393 if c == '\'':
394 path = path[index + 1:]
395 pathlen = len(path)
396 try:
397 index = path.index('\'')
398 res = res + '\'' + path[:index + 1]
399 except ValueError:
400 res = res + path
401 index = pathlen - 1
402 elif c == '$':
403 if path[index + 1:index + 2] == '$':
404 res = res + c
405 index = index + 1
406 elif path[index + 1:index + 2] == '{':
407 path = path[index+2:]
408 pathlen = len(path)
409 try:
410 index = path.index('}')
411 var = path[:index]
412 if var in os.environ:
413 res = res + os.environ[var]
414 except ValueError:
415 res = res + path
416 index = pathlen - 1
417 else:
418 var = ''
419 index = index + 1
420 c = path[index:index + 1]
421 while c != '' and c in varchars:
422 var = var + c
423 index = index + 1
424 c = path[index:index + 1]
425 if var in os.environ:
426 res = res + os.environ[var]
427 if c != '':
428 res = res + c
429 else:
430 res = res + c
431 index = index + 1
432 return res
433
434
435
436
437
438
440 """Normalize path, eliminating double slashes, etc."""
441 path = path.replace("/", "\\")
442 prefix, path = splitdrive(path)
443
444
445
446
447
448
449
450
451
452 if prefix == '':
453
454 while path[:1] == "\\":
455 prefix = prefix + "\\"
456 path = path[1:]
457 else:
458
459 if path.startswith("\\"):
460 prefix = prefix + "\\"
461 path = path.lstrip("\\")
462 comps = path.split("\\")
463 i = 0
464 while i < len(comps):
465 if comps[i] in ('.', ''):
466 del comps[i]
467 elif comps[i] == '..':
468 if i > 0 and comps[i-1] != '..':
469 del comps[i-1:i+1]
470 i -= 1
471 elif i == 0 and prefix.endswith("\\"):
472 del comps[i]
473 else:
474 i += 1
475 else:
476 i += 1
477
478 if not prefix and not comps:
479 comps.append('.')
480 return prefix + "\\".join(comps)
481
482
483
484 try:
485 from nt import _getfullpathname
486
487 except ImportError:
489 """Return the absolute version of a path."""
490 if not isabs(path):
491 path = join(os.getcwd(), path)
492 return normpath(path)
493
494 else:
496 """Return the absolute version of a path."""
497
498 if path:
499 try:
500 path = _getfullpathname(path)
501 except WindowsError:
502 pass
503 else:
504 path = os.getcwd()
505 return normpath(path)
506
507
508 realpath = abspath
509
510 supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
511 sys.getwindowsversion()[3] >= 2)
512