1 # Module 'ntpath' -- common operations on WinNT/Win95 pathnames
2 """Common pathname manipulations, WindowsNT/95 version.
4 Instead of importing this module directly, import os and refer to this
11 __all__
= ["normcase","isabs","join","splitdrive","split","splitext",
12 "basename","dirname","commonprefix","getsize","getmtime",
13 "getatime","islink","exists","isdir","isfile","ismount",
14 "walk","expanduser","expandvars","normpath","abspath","splitunc"]
16 # Normalize the case of a pathname and map slashes to backslashes.
17 # Other normalizations (such as optimizing '../' away) are not done
18 # (this is done by normpath).
21 """Normalize case of pathname.
23 Makes all characters lowercase and all slashes into backslashes."""
24 return s
.replace("/", "\\").lower()
27 # Return whether a path is absolute.
28 # Trivial in Posix, harder on the Mac or MS-DOS.
29 # For DOS it is absolute if it starts with a slash or backslash (current
30 # volume), or if a pathname after the volume letter and colon / UNC resource
31 # starts with a slash or backslash.
34 """Test whether a path is absolute"""
36 return s
!= '' and s
[:1] in '/\\'
39 # Join two (or more) paths.
42 """Join two or more pathname components, inserting "\\" as needed"""
45 b_wins
= 0 # set to 1 iff b makes path irrelevant
50 # This probably wipes out path so far. However, it's more
51 # complicated if path begins with a drive letter:
52 # 1. join('c:', '/a') == 'c:/a'
53 # 2. join('c:/', '/a') == 'c:/a'
55 # 3. join('c:/a', '/b') == '/b'
56 # 4. join('c:', 'd:/') = 'd:/'
57 # 5. join('c:/', 'd:/') = 'd:/'
58 if path
[1:2] != ":" or b
[1:2] == ":":
59 # Path doesn't start with a drive letter, or cases 4 and 5.
62 # Else path has a drive letter, and b doesn't but is absolute.
63 elif len(path
) > 3 or (len(path
) == 3 and
64 path
[-1] not in "/\\"):
71 # Join, and ensure there's a separator.
74 if b
and b
[0] in "/\\":
86 # path is not empty and does not end with a backslash,
87 # but b is empty; since, e.g., split('a/') produces
88 # ('a', ''), it's best if join() adds a backslash in
95 # Split a path in a drive specification (a drive letter followed by a
96 # colon) and the path specification.
97 # It is always true that drivespec + pathspec == p
99 """Split a pathname into drive and path specifiers. Returns a 2-tuple
100 "(drive,path)"; either part may be empty"""
108 """Split a pathname into UNC mount point and relative path specifiers.
110 Return a 2-tuple (unc, rest); either part may be empty.
111 If unc is not empty, it has the form '//host/mount' (or similar
112 using backslashes). unc+rest is always the input path.
113 Paths containing drive letters never have an UNC part.
116 return '', p
# Drive letter present
118 if firstTwo
== '//' or firstTwo
== '\\\\':
120 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
121 # \\machine\mountpoint\directories...
122 # directory ^^^^^^^^^^^^^^^
124 index
= normp
.find('\\', 2)
126 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
128 index
= normp
.find('\\', index
+ 1)
131 return p
[:index
], p
[index
:]
135 # Split a path in head (everything up to the last '/') and tail (the
136 # rest). After the trailing '/' is stripped, the invariant
137 # join(head, tail) == p holds.
138 # The resulting head won't end in '/' unless it is the root.
143 Return tuple (head, tail) where tail is everything after the final slash.
144 Either part may be empty."""
147 # set i to index beyond p's last slash
149 while i
and p
[i
-1] not in '/\\':
151 head
, tail
= p
[:i
], p
[i
:] # now tail has no slashes
152 # remove trailing slashes from head, unless it's all slashes
154 while head2
and head2
[-1] in '/\\':
157 return d
+ head
, tail
160 # Split a path in root and extension.
161 # The extension is everything starting at the last dot in the last
162 # pathname component; the root is everything before that.
163 # It is always true that root + ext == p.
166 """Split the extension from a pathname.
168 Extension is everything from the last dot to the end.
169 Return (root, ext), either part may be empty."""
173 root
, ext
= root
+ ext
+ c
, ''
176 root
, ext
= root
+ ext
, c
186 # Return the tail (basename) part of a path.
189 """Returns the final component of a pathname"""
193 # Return the head (dirname) part of a path.
196 """Returns the directory component of a pathname"""
200 # Return the longest prefix of all list elements.
203 "Given a list of pathnames, returns the longest common leading component"
207 for i
in range(len(prefix
)):
208 if prefix
[:i
+1] != item
[:i
+1]:
215 # Get size, mtime, atime of files.
217 def getsize(filename
):
218 """Return the size of a file, reported by os.stat()"""
219 st
= os
.stat(filename
)
220 return st
[stat
.ST_SIZE
]
222 def getmtime(filename
):
223 """Return the last modification time of a file, reported by os.stat()"""
224 st
= os
.stat(filename
)
225 return st
[stat
.ST_MTIME
]
227 def getatime(filename
):
228 """Return the last access time of a file, reported by os.stat()"""
229 st
= os
.stat(filename
)
230 return st
[stat
.ST_ATIME
]
233 # Is a path a symbolic link?
234 # This will always return false on systems where posix.lstat doesn't exist.
237 """Test for symbolic link. On WindowsNT/95 always returns false"""
242 # This is false for dangling symbolic links.
245 """Test whether a path exists"""
253 # Is a path a dos directory?
254 # This follows symbolic links, so both islink() and isdir() can be true
258 """Test whether a path is a directory"""
263 return stat
.S_ISDIR(st
[stat
.ST_MODE
])
266 # Is a path a regular file?
267 # This follows symbolic links, so both islink() and isdir() can be true
271 """Test whether a path is a regular file"""
276 return stat
.S_ISREG(st
[stat
.ST_MODE
])
279 # Is a path a mount point? Either a root (with or without drive letter)
280 # or an UNC path with at most a / or \ after the mount point.
283 """Test whether a path is a mount point (defined as root of drive)"""
284 unc
, rest
= splitunc(path
)
286 return rest
in ("", "/", "\\")
287 p
= splitdrive(path
)[1]
288 return len(p
) == 1 and p
[0] in '/\\'
291 # Directory tree walk.
292 # For each directory under top (including top itself, but excluding
293 # '.' and '..'), func(arg, dirname, filenames) is called, where
294 # dirname is the name of the directory and filenames is the list
295 # files files (and subdirectories etc.) in the directory.
296 # The func may modify the filenames list, to implement a filter,
297 # or to impose a different order of visiting.
299 def walk(top
, func
, arg
):
300 """Directory tree walk with callback function.
302 For each directory in the directory tree rooted at top (including top
303 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
304 dirname is the name of the directory, and fnames a list of the names of
305 the files and subdirectories in dirname (excluding '.' and '..'). func
306 may modify the fnames list in-place (e.g. via del or slice assignment),
307 and walk will only recurse into the subdirectories whose names remain in
308 fnames; this can be used to implement a filter, or to impose a specific
309 order of visiting. No semantics are defined for, or required of, arg,
310 beyond that arg is always passed to func. It can be used, e.g., to pass
311 a filename pattern, or a mutable object designed to accumulate
312 statistics. Passing None for arg is common."""
315 names
= os
.listdir(top
)
318 func(arg
, top
, names
)
319 exceptions
= ('.', '..')
321 if name
not in exceptions
:
322 name
= join(top
, name
)
324 walk(name
, func
, arg
)
327 # Expand paths beginning with '~' or '~user'.
328 # '~' means $HOME; '~user' means that user's home directory.
329 # If the path doesn't begin with '~', or if the user or $HOME is unknown,
330 # the path is returned unchanged (leaving error reporting to whatever
331 # function is called with the expanded path as argument).
332 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
333 # (A function should also be defined to do full *sh-style environment
334 # variable expansion.)
336 def expanduser(path
):
337 """Expand ~ and ~user constructs.
339 If user or $HOME is unknown, do nothing."""
343 while i
< n
and path
[i
] not in '/\\':
346 if os
.environ
.has_key('HOME'):
347 userhome
= os
.environ
['HOME']
348 elif not os
.environ
.has_key('HOMEPATH'):
352 drive
= os
.environ
['HOMEDRIVE']
355 userhome
= join(drive
, os
.environ
['HOMEPATH'])
358 return userhome
+ path
[i
:]
361 # Expand paths containing shell variable substitutions.
362 # The following rules apply:
363 # - no expansion within single quotes
364 # - no escape character, except for '$$' which is translated into '$'
365 # - ${varname} is accepted.
366 # - varnames can be made out of letters, digits and the character '_'
367 # XXX With COMMAND.COM you can use any characters in a variable name,
368 # XXX except '^|<>='.
370 def expandvars(path
):
371 """Expand shell variables of form $var and ${var}.
373 Unknown variables are left unchanged."""
377 varchars
= string
.ascii_letters
+ string
.digits
+ '_-'
381 while index
< pathlen
:
383 if c
== '\'': # no expansion within single quotes
384 path
= path
[index
+ 1:]
387 index
= path
.index('\'')
388 res
= res
+ '\'' + path
[:index
+ 1]
392 elif c
== '$': # variable or '$$'
393 if path
[index
+ 1:index
+ 2] == '$':
396 elif path
[index
+ 1:index
+ 2] == '{':
397 path
= path
[index
+2:]
400 index
= path
.index('}')
402 if os
.environ
.has_key(var
):
403 res
= res
+ os
.environ
[var
]
410 c
= path
[index
:index
+ 1]
411 while c
!= '' and c
in varchars
:
414 c
= path
[index
:index
+ 1]
415 if os
.environ
.has_key(var
):
416 res
= res
+ os
.environ
[var
]
425 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
426 # Previously, this function also truncated pathnames to 8+3 format,
427 # but as this module is called "ntpath", that's obviously wrong!
430 """Normalize path, eliminating double slashes, etc."""
431 path
= path
.replace("/", "\\")
432 prefix
, path
= splitdrive(path
)
433 while path
[:1] == "\\":
434 prefix
= prefix
+ "\\"
436 comps
= path
.split("\\")
438 while i
< len(comps
):
439 if comps
[i
] in ('.', ''):
441 elif comps
[i
] == '..':
442 if i
> 0 and comps
[i
-1] != '..':
445 elif i
== 0 and prefix
.endswith("\\"):
451 # If the path is now empty, substitute '.'
452 if not prefix
and not comps
:
454 return prefix
+ "\\".join(comps
)
457 # Return an absolute path.
459 """Return the absolute version of a path"""
460 if path
: # Empty path must return current working directory.
461 from nt
import _getfullpathname
463 path
= _getfullpathname(path
)
465 pass # Bad path - return unchanged.
468 return normpath(path
)
470 # realpath is a no-op on systems without islink support