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
12 __all__
= ["normcase","isabs","join","splitdrive","split","splitext",
13 "basename","dirname","commonprefix","getsize","getmtime",
14 "getatime","getctime", "islink","exists","isdir","isfile","ismount",
15 "walk","expanduser","expandvars","normpath","abspath","splitunc",
16 "supports_unicode_filenames"]
18 # Normalize the case of a pathname and map slashes to backslashes.
19 # Other normalizations (such as optimizing '../' away) are not done
20 # (this is done by normpath).
23 """Normalize case of pathname.
25 Makes all characters lowercase and all slashes into backslashes."""
26 return s
.replace("/", "\\").lower()
29 # Return whether a path is absolute.
30 # Trivial in Posix, harder on the Mac or MS-DOS.
31 # For DOS it is absolute if it starts with a slash or backslash (current
32 # volume), or if a pathname after the volume letter and colon / UNC resource
33 # starts with a slash or backslash.
36 """Test whether a path is absolute"""
38 return s
!= '' and s
[:1] in '/\\'
41 # Join two (or more) paths.
44 """Join two or more pathname components, inserting "\\" as needed"""
47 b_wins
= 0 # set to 1 iff b makes path irrelevant
52 # This probably wipes out path so far. However, it's more
53 # complicated if path begins with a drive letter:
54 # 1. join('c:', '/a') == 'c:/a'
55 # 2. join('c:/', '/a') == 'c:/a'
57 # 3. join('c:/a', '/b') == '/b'
58 # 4. join('c:', 'd:/') = 'd:/'
59 # 5. join('c:/', 'd:/') = 'd:/'
60 if path
[1:2] != ":" or b
[1:2] == ":":
61 # Path doesn't start with a drive letter, or cases 4 and 5.
64 # Else path has a drive letter, and b doesn't but is absolute.
65 elif len(path
) > 3 or (len(path
) == 3 and
66 path
[-1] not in "/\\"):
73 # Join, and ensure there's a separator.
76 if b
and b
[0] in "/\\":
88 # path is not empty and does not end with a backslash,
89 # but b is empty; since, e.g., split('a/') produces
90 # ('a', ''), it's best if join() adds a backslash in
97 # Split a path in a drive specification (a drive letter followed by a
98 # colon) and the path specification.
99 # It is always true that drivespec + pathspec == p
101 """Split a pathname into drive and path specifiers. Returns a 2-tuple
102 "(drive,path)"; either part may be empty"""
110 """Split a pathname into UNC mount point and relative path specifiers.
112 Return a 2-tuple (unc, rest); either part may be empty.
113 If unc is not empty, it has the form '//host/mount' (or similar
114 using backslashes). unc+rest is always the input path.
115 Paths containing drive letters never have an UNC part.
118 return '', p
# Drive letter present
120 if firstTwo
== '//' or firstTwo
== '\\\\':
122 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
123 # \\machine\mountpoint\directories...
124 # directory ^^^^^^^^^^^^^^^
126 index
= normp
.find('\\', 2)
128 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
130 index
= normp
.find('\\', index
+ 1)
133 return p
[:index
], p
[index
:]
137 # Split a path in head (everything up to the last '/') and tail (the
138 # rest). After the trailing '/' is stripped, the invariant
139 # join(head, tail) == p holds.
140 # The resulting head won't end in '/' unless it is the root.
145 Return tuple (head, tail) where tail is everything after the final slash.
146 Either part may be empty."""
149 # set i to index beyond p's last slash
151 while i
and p
[i
-1] not in '/\\':
153 head
, tail
= p
[:i
], p
[i
:] # now tail has no slashes
154 # remove trailing slashes from head, unless it's all slashes
156 while head2
and head2
[-1] in '/\\':
159 return d
+ head
, tail
162 # Split a path in root and extension.
163 # The extension is everything starting at the last dot in the last
164 # pathname component; the root is everything before that.
165 # It is always true that root + ext == p.
168 """Split the extension from a pathname.
170 Extension is everything from the last dot to the end.
171 Return (root, ext), either part may be empty."""
174 if i
<=max(p
.rfind('/'), p
.rfind('\\')):
180 # Return the tail (basename) part of a path.
183 """Returns the final component of a pathname"""
187 # Return the head (dirname) part of a path.
190 """Returns the directory component of a pathname"""
194 # Return the longest prefix of all list elements.
197 "Given a list of pathnames, returns the longest common leading component"
201 for i
in range(len(prefix
)):
202 if prefix
[:i
+1] != item
[:i
+1]:
209 # Get size, mtime, atime of files.
211 def getsize(filename
):
212 """Return the size of a file, reported by os.stat()"""
213 return os
.stat(filename
).st_size
215 def getmtime(filename
):
216 """Return the last modification time of a file, reported by os.stat()"""
217 return os
.stat(filename
).st_mtime
219 def getatime(filename
):
220 """Return the last access time of a file, reported by os.stat()"""
221 return os
.stat(filename
).st_atime
223 def getctime(filename
):
224 """Return the creation time of a file, reported by os.stat()."""
225 return os
.stat(filename
).st_ctime
227 # Is a path a symbolic link?
228 # This will always return false on systems where posix.lstat doesn't exist.
231 """Test for symbolic link. On WindowsNT/95 always returns false"""
236 # This is false for dangling symbolic links.
239 """Test whether a path exists"""
247 # Is a path a dos directory?
248 # This follows symbolic links, so both islink() and isdir() can be true
252 """Test whether a path is a directory"""
257 return stat
.S_ISDIR(st
.st_mode
)
260 # Is a path a regular file?
261 # This follows symbolic links, so both islink() and isdir() can be true
265 """Test whether a path is a regular file"""
270 return stat
.S_ISREG(st
.st_mode
)
273 # Is a path a mount point? Either a root (with or without drive letter)
274 # or an UNC path with at most a / or \ after the mount point.
277 """Test whether a path is a mount point (defined as root of drive)"""
278 unc
, rest
= splitunc(path
)
280 return rest
in ("", "/", "\\")
281 p
= splitdrive(path
)[1]
282 return len(p
) == 1 and p
[0] in '/\\'
285 # Directory tree walk.
286 # For each directory under top (including top itself, but excluding
287 # '.' and '..'), func(arg, dirname, filenames) is called, where
288 # dirname is the name of the directory and filenames is the list
289 # files files (and subdirectories etc.) in the directory.
290 # The func may modify the filenames list, to implement a filter,
291 # or to impose a different order of visiting.
293 def walk(top
, func
, arg
):
294 """Directory tree walk with callback function.
296 For each directory in the directory tree rooted at top (including top
297 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
298 dirname is the name of the directory, and fnames a list of the names of
299 the files and subdirectories in dirname (excluding '.' and '..'). func
300 may modify the fnames list in-place (e.g. via del or slice assignment),
301 and walk will only recurse into the subdirectories whose names remain in
302 fnames; this can be used to implement a filter, or to impose a specific
303 order of visiting. No semantics are defined for, or required of, arg,
304 beyond that arg is always passed to func. It can be used, e.g., to pass
305 a filename pattern, or a mutable object designed to accumulate
306 statistics. Passing None for arg is common."""
309 names
= os
.listdir(top
)
312 func(arg
, top
, names
)
313 exceptions
= ('.', '..')
315 if name
not in exceptions
:
316 name
= join(top
, name
)
318 walk(name
, func
, arg
)
321 # Expand paths beginning with '~' or '~user'.
322 # '~' means $HOME; '~user' means that user's home directory.
323 # If the path doesn't begin with '~', or if the user or $HOME is unknown,
324 # the path is returned unchanged (leaving error reporting to whatever
325 # function is called with the expanded path as argument).
326 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
327 # (A function should also be defined to do full *sh-style environment
328 # variable expansion.)
330 def expanduser(path
):
331 """Expand ~ and ~user constructs.
333 If user or $HOME is unknown, do nothing."""
337 while i
< n
and path
[i
] not in '/\\':
340 if 'HOME' in os
.environ
:
341 userhome
= os
.environ
['HOME']
342 elif not 'HOMEPATH' in os
.environ
:
346 drive
= os
.environ
['HOMEDRIVE']
349 userhome
= join(drive
, os
.environ
['HOMEPATH'])
352 return userhome
+ path
[i
:]
355 # Expand paths containing shell variable substitutions.
356 # The following rules apply:
357 # - no expansion within single quotes
358 # - no escape character, except for '$$' which is translated into '$'
359 # - ${varname} is accepted.
360 # - varnames can be made out of letters, digits and the character '_'
361 # XXX With COMMAND.COM you can use any characters in a variable name,
362 # XXX except '^|<>='.
364 def expandvars(path
):
365 """Expand shell variables of form $var and ${var}.
367 Unknown variables are left unchanged."""
371 varchars
= string
.ascii_letters
+ string
.digits
+ '_-'
375 while index
< pathlen
:
377 if c
== '\'': # no expansion within single quotes
378 path
= path
[index
+ 1:]
381 index
= path
.index('\'')
382 res
= res
+ '\'' + path
[:index
+ 1]
386 elif c
== '$': # variable or '$$'
387 if path
[index
+ 1:index
+ 2] == '$':
390 elif path
[index
+ 1:index
+ 2] == '{':
391 path
= path
[index
+2:]
394 index
= path
.index('}')
396 if var
in os
.environ
:
397 res
= res
+ os
.environ
[var
]
404 c
= path
[index
:index
+ 1]
405 while c
!= '' and c
in varchars
:
408 c
= path
[index
:index
+ 1]
409 if var
in os
.environ
:
410 res
= res
+ os
.environ
[var
]
419 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
420 # Previously, this function also truncated pathnames to 8+3 format,
421 # but as this module is called "ntpath", that's obviously wrong!
424 """Normalize path, eliminating double slashes, etc."""
425 path
= path
.replace("/", "\\")
426 prefix
, path
= splitdrive(path
)
427 while path
[:1] == "\\":
428 prefix
= prefix
+ "\\"
430 comps
= path
.split("\\")
432 while i
< len(comps
):
433 if comps
[i
] in ('.', ''):
435 elif comps
[i
] == '..':
436 if i
> 0 and comps
[i
-1] != '..':
439 elif i
== 0 and prefix
.endswith("\\"):
445 # If the path is now empty, substitute '.'
446 if not prefix
and not comps
:
448 return prefix
+ "\\".join(comps
)
451 # Return an absolute path.
453 """Return the absolute version of a path"""
455 from nt
import _getfullpathname
456 except ImportError: # Not running on Windows - mock up something sensible.
460 path
= join(os
.getcwd(), path
)
461 return normpath(path
)
463 return _abspath(path
)
465 if path
: # Empty path must return current working directory.
467 path
= _getfullpathname(path
)
469 pass # Bad path - return unchanged.
472 return normpath(path
)
474 # realpath is a no-op on systems without islink support
476 # Win9x family and earlier have no Unicode filename support.
477 supports_unicode_filenames
= (hasattr(sys
, "getwindowsversion") and
478 sys
.getwindowsversion()[3] >= 2)