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","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"]
19 # strings representing various path-related bits and pieces
27 if 'ce' in sys
.builtin_module_names
:
29 elif 'os2' in sys
.builtin_module_names
:
34 # Normalize the case of a pathname and map slashes to backslashes.
35 # Other normalizations (such as optimizing '../' away) are not done
36 # (this is done by normpath).
39 """Normalize case of pathname.
41 Makes all characters lowercase and all slashes into backslashes."""
42 return s
.replace("/", "\\").lower()
45 # Return whether a path is absolute.
46 # Trivial in Posix, harder on the Mac or MS-DOS.
47 # For DOS it is absolute if it starts with a slash or backslash (current
48 # volume), or if a pathname after the volume letter and colon / UNC resource
49 # starts with a slash or backslash.
52 """Test whether a path is absolute"""
54 return s
!= '' and s
[:1] in '/\\'
57 # Join two (or more) paths.
60 """Join two or more pathname components, inserting "\\" as needed"""
63 b_wins
= 0 # set to 1 iff b makes path irrelevant
68 # This probably wipes out path so far. However, it's more
69 # complicated if path begins with a drive letter:
70 # 1. join('c:', '/a') == 'c:/a'
71 # 2. join('c:/', '/a') == 'c:/a'
73 # 3. join('c:/a', '/b') == '/b'
74 # 4. join('c:', 'd:/') = 'd:/'
75 # 5. join('c:/', 'd:/') = 'd:/'
76 if path
[1:2] != ":" or b
[1:2] == ":":
77 # Path doesn't start with a drive letter, or cases 4 and 5.
80 # Else path has a drive letter, and b doesn't but is absolute.
81 elif len(path
) > 3 or (len(path
) == 3 and
82 path
[-1] not in "/\\"):
89 # Join, and ensure there's a separator.
92 if b
and b
[0] in "/\\":
104 # path is not empty and does not end with a backslash,
105 # but b is empty; since, e.g., split('a/') produces
106 # ('a', ''), it's best if join() adds a backslash in
113 # Split a path in a drive specification (a drive letter followed by a
114 # colon) and the path specification.
115 # It is always true that drivespec + pathspec == p
117 """Split a pathname into drive and path specifiers. Returns a 2-tuple
118 "(drive,path)"; either part may be empty"""
126 """Split a pathname into UNC mount point and relative path specifiers.
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.
134 return '', p
# Drive letter present
136 if firstTwo
== '//' or firstTwo
== '\\\\':
138 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
139 # \\machine\mountpoint\directories...
140 # directory ^^^^^^^^^^^^^^^
142 index
= normp
.find('\\', 2)
144 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
146 index
= normp
.find('\\', index
+ 1)
149 return p
[:index
], p
[index
:]
153 # Split a path in head (everything up to the last '/') and tail (the
154 # rest). After the trailing '/' is stripped, the invariant
155 # join(head, tail) == p holds.
156 # The resulting head won't end in '/' unless it is the root.
161 Return tuple (head, tail) where tail is everything after the final slash.
162 Either part may be empty."""
165 # set i to index beyond p's last slash
167 while i
and p
[i
-1] not in '/\\':
169 head
, tail
= p
[:i
], p
[i
:] # now tail has no slashes
170 # remove trailing slashes from head, unless it's all slashes
172 while head2
and head2
[-1] in '/\\':
175 return d
+ head
, tail
178 # Split a path in root and extension.
179 # The extension is everything starting at the last dot in the last
180 # pathname component; the root is everything before that.
181 # It is always true that root + ext == p.
184 """Split the extension from a pathname.
186 Extension is everything from the last dot to the end.
187 Return (root, ext), either part may be empty."""
190 if i
<=max(p
.rfind('/'), p
.rfind('\\')):
196 # Return the tail (basename) part of a path.
199 """Returns the final component of a pathname"""
203 # Return the head (dirname) part of a path.
206 """Returns the directory component of a pathname"""
210 # Return the longest prefix of all list elements.
213 "Given a list of pathnames, returns the longest common leading component"
217 n
= min(len(s1
), len(s2
))
224 # Get size, mtime, atime of files.
226 def getsize(filename
):
227 """Return the size of a file, reported by os.stat()"""
228 return os
.stat(filename
).st_size
230 def getmtime(filename
):
231 """Return the last modification time of a file, reported by os.stat()"""
232 return os
.stat(filename
).st_mtime
234 def getatime(filename
):
235 """Return the last access time of a file, reported by os.stat()"""
236 return os
.stat(filename
).st_atime
238 def getctime(filename
):
239 """Return the creation time of a file, reported by os.stat()."""
240 return os
.stat(filename
).st_ctime
242 # Is a path a symbolic link?
243 # This will always return false on systems where posix.lstat doesn't exist.
246 """Test for symbolic link. On WindowsNT/95 always returns false"""
253 """Test whether a path exists"""
263 # Is a path a dos directory?
264 # This follows symbolic links, so both islink() and isdir() can be true
268 """Test whether a path is a directory"""
273 return stat
.S_ISDIR(st
.st_mode
)
276 # Is a path a regular file?
277 # This follows symbolic links, so both islink() and isdir() can be true
281 """Test whether a path is a regular file"""
286 return stat
.S_ISREG(st
.st_mode
)
289 # Is a path a mount point? Either a root (with or without drive letter)
290 # or an UNC path with at most a / or \ after the mount point.
293 """Test whether a path is a mount point (defined as root of drive)"""
294 unc
, rest
= splitunc(path
)
296 return rest
in ("", "/", "\\")
297 p
= splitdrive(path
)[1]
298 return len(p
) == 1 and p
[0] in '/\\'
301 # Directory tree walk.
302 # For each directory under top (including top itself, but excluding
303 # '.' and '..'), func(arg, dirname, filenames) is called, where
304 # dirname is the name of the directory and filenames is the list
305 # of files (and subdirectories etc.) in the directory.
306 # The func may modify the filenames list, to implement a filter,
307 # or to impose a different order of visiting.
309 def walk(top
, func
, arg
):
310 """Directory tree walk with callback function.
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."""
325 names
= os
.listdir(top
)
328 func(arg
, top
, names
)
329 exceptions
= ('.', '..')
331 if name
not in exceptions
:
332 name
= join(top
, name
)
334 walk(name
, func
, arg
)
337 # Expand paths beginning with '~' or '~user'.
338 # '~' means $HOME; '~user' means that user's home directory.
339 # If the path doesn't begin with '~', or if the user or $HOME is unknown,
340 # the path is returned unchanged (leaving error reporting to whatever
341 # function is called with the expanded path as argument).
342 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
343 # (A function should also be defined to do full *sh-style environment
344 # variable expansion.)
346 def expanduser(path
):
347 """Expand ~ and ~user constructs.
349 If user or $HOME is unknown, do nothing."""
353 while i
< n
and path
[i
] not in '/\\':
356 if 'HOME' in os
.environ
:
357 userhome
= os
.environ
['HOME']
358 elif not 'HOMEPATH' in os
.environ
:
362 drive
= os
.environ
['HOMEDRIVE']
365 userhome
= join(drive
, os
.environ
['HOMEPATH'])
368 return userhome
+ path
[i
:]
371 # Expand paths containing shell variable substitutions.
372 # The following rules apply:
373 # - no expansion within single quotes
374 # - no escape character, except for '$$' which is translated into '$'
375 # - ${varname} is accepted.
376 # - varnames can be made out of letters, digits and the character '_'
377 # XXX With COMMAND.COM you can use any characters in a variable name,
378 # XXX except '^|<>='.
380 def expandvars(path
):
381 """Expand shell variables of form $var and ${var}.
383 Unknown variables are left unchanged."""
387 varchars
= string
.ascii_letters
+ string
.digits
+ '_-'
391 while index
< pathlen
:
393 if c
== '\'': # no expansion within single quotes
394 path
= path
[index
+ 1:]
397 index
= path
.index('\'')
398 res
= res
+ '\'' + path
[:index
+ 1]
402 elif c
== '$': # variable or '$$'
403 if path
[index
+ 1:index
+ 2] == '$':
406 elif path
[index
+ 1:index
+ 2] == '{':
407 path
= path
[index
+2:]
410 index
= path
.index('}')
412 if var
in os
.environ
:
413 res
= res
+ os
.environ
[var
]
420 c
= path
[index
:index
+ 1]
421 while c
!= '' and c
in varchars
:
424 c
= path
[index
:index
+ 1]
425 if var
in os
.environ
:
426 res
= res
+ os
.environ
[var
]
435 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
436 # Previously, this function also truncated pathnames to 8+3 format,
437 # but as this module is called "ntpath", that's obviously wrong!
440 """Normalize path, eliminating double slashes, etc."""
441 path
= path
.replace("/", "\\")
442 prefix
, path
= splitdrive(path
)
443 # We need to be careful here. If the prefix is empty, and the path starts
444 # with a backslash, it could either be an absolute path on the current
445 # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
446 # is therefore imperative NOT to collapse multiple backslashes blindly in
448 # The code below preserves multiple backslashes when there is no drive
449 # letter. This means that the invalid filename \\\a\b is preserved
450 # unchanged, where a\\\b is normalised to a\b. It's not clear that there
451 # is any better behaviour for such edge cases.
453 # No drive letter - preserve initial backslashes
454 while path
[:1] == "\\":
455 prefix
= prefix
+ "\\"
458 # We have a drive letter - collapse initial backslashes
459 if path
.startswith("\\"):
460 prefix
= prefix
+ "\\"
461 path
= path
.lstrip("\\")
462 comps
= path
.split("\\")
464 while i
< len(comps
):
465 if comps
[i
] in ('.', ''):
467 elif comps
[i
] == '..':
468 if i
> 0 and comps
[i
-1] != '..':
471 elif i
== 0 and prefix
.endswith("\\"):
477 # If the path is now empty, substitute '.'
478 if not prefix
and not comps
:
480 return prefix
+ "\\".join(comps
)
483 # Return an absolute path.
485 from nt
import _getfullpathname
487 except ImportError: # not running on Windows - mock up something sensible
489 """Return the absolute version of a path."""
491 path
= join(os
.getcwd(), path
)
492 return normpath(path
)
494 else: # use native Windows method on Windows
496 """Return the absolute version of a path."""
498 if path
: # Empty path must return current working directory.
500 path
= _getfullpathname(path
)
502 pass # Bad path - return unchanged.
505 return normpath(path
)
507 # realpath is a no-op on systems without islink support
509 # Win9x family and earlier have no Unicode filename support.
510 supports_unicode_filenames
= (hasattr(sys
, "getwindowsversion") and
511 sys
.getwindowsversion()[3] >= 2)