Module ntpath |
[hide private]
[frames] | no frames]

# Source Code for Module ntpath

      1  # Module 'ntpath' -- common operations on WinNT/Win95 pathnames
      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  # strings representing various path-related bits and pieces
     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      # OS/2 w/ VACPP
     31      altsep = '/'
     32  devnull = 'nul'
     33
     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).
     37
     38 -def normcase(s):
     39      """Normalize case of pathname.
     40
     41      Makes all characters lowercase and all slashes into backslashes."""
     42      return s.replace("/", "\\").lower()
     43
     44
     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.
     50
     51 -def isabs(s):
     52      """Test whether a path is absolute"""
     53      s = splitdrive(s)[1]
     54      return s != '' and s[:1] in '/\\'
     55
     56
     57  # Join two (or more) paths.
     58
     59 -def join(a, *p):
     60      """Join two or more pathname components, inserting "\\" as needed"""
     61      path = a
     62      for b in p:
     63          b_wins = 0  # set to 1 iff b makes path irrelevant
     64          if path == "":
     65              b_wins = 1
     66
     67          elif isabs(b):
     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'
     72              # But
     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.
     78                  b_wins = 1
     79
     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 "/\\"):
     83                  # case 3
     84                  b_wins = 1
     85
     86          if b_wins:
     87              path = b
     88          else:
     89              # Join, and ensure there's a separator.
     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                  # 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
    107                  # this case.
    108                  path += '\\'
    109
    110      return path
    111
    112
    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
    116 -def splitdrive(p):
    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  # Parse UNC paths
    125 -def splitunc(p):
    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 # Drive letter present
    135      firstTwo = p[0:2]
    136      if firstTwo == '//' or firstTwo == '\\\\':
    137          # is a UNC path:
    138          # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
    139          # \\machine\mountpoint\directories...
    140          #           directory ^^^^^^^^^^^^^^^
    141          normp = normcase(p)
    142          index = normp.find('\\', 2)
    143          if index == -1:
    144              ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
    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  # 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.
    157
    158 -def split(p):
    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      # set i to index beyond p's last slash
    166      i = len(p)
    167      while i and p[i-1] not in '/\\':
    168          i = i - 1
    169      head, tail = p[:i], p[i:]  # now tail has no slashes
    170      # remove trailing slashes from head, unless it's all slashes
    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  # 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.
    182
    183 -def splitext(p):
    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  # Return the tail (basename) part of a path.
    197
    198 -def basename(p):
    199      """Returns the final component of a pathname"""
    200      return split(p)[1]
    201
    202
    203  # Return the head (dirname) part of a path.
    204
    205 -def dirname(p):
    206      """Returns the directory component of a pathname"""
    207      return split(p)[0]
    208
    209
    210  # Return the longest prefix of all list elements.
    211
    212 -def commonprefix(m):
    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  # Get size, mtime, atime of files.
    225
    226 -def getsize(filename):
    227      """Return the size of a file, reported by os.stat()"""
    228      return os.stat(filename).st_size
    229
    230 -def getmtime(filename):
    231      """Return the last modification time of a file, reported by os.stat()"""
    232      return os.stat(filename).st_mtime
    233
    234 -def getatime(filename):
    235      """Return the last access time of a file, reported by os.stat()"""
    236      return os.stat(filename).st_atime
    237
    238 -def getctime(filename):
    239      """Return the creation time of a file, reported by os.stat()."""
    240      return os.stat(filename).st_ctime
    241
    242  # Is a path a symbolic link?
    243  # This will always return false on systems where posix.lstat doesn't exist.
    244
    245 -def islink(path):
    246      """Test for symbolic link.  On WindowsNT/95 always returns false"""
    247      return False
    248
    249
    250  # Does a path exist?
    251
    252 -def exists(path):
    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  # Is a path a dos directory?
    264  # This follows symbolic links, so both islink() and isdir() can be true
    265  # for the same path.
    266
    267 -def isdir(path):
    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  # Is a path a regular file?
    277  # This follows symbolic links, so both islink() and isdir() can be true
    278  # for the same path.
    279
    280 -def isfile(path):
    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  # 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.
    291
    292 -def ismount(path):
    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  # 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.
    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  # 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.)
    345
    346 -def expanduser(path):
    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  # 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 '^|<>='.
    379
    380 -def expandvars(path):
    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 == '\'':   # no expansion within single quotes
    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 == '$':  # variable or '$$'
    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  # 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!
    438
    439 -def normpath(path):
    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
    447      # that case.
    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.
    452      if prefix == '':
    453          # No drive letter - preserve initial backslashes
    454          while path[:1] == "\\":
    455              prefix = prefix + "\\"
    456              path = path[1:]
    457      else:
    458          # We have a drive letter - collapse initial backslashes
    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      # If the path is now empty, substitute '.'
    478      if not prefix and not comps:
    479          comps.append('.')
    480      return prefix + "\\".join(comps)
    481
    482
    483  # Return an absolute path.
    484  try:
    485      from nt import _getfullpathname
    486
    487  except ImportError: # not running on Windows - mock up something sensible
    488 -    def abspath(path):
    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:  # use native Windows method on Windows
    495 -    def abspath(path):
    496          """Return the absolute version of a path."""
    497
    498          if path: # Empty path must return current working directory.
    499              try:
    500                  path = _getfullpathname(path)
    501              except WindowsError:
    502                  pass # Bad path - return unchanged.
    503          else:
    504              path = os.getcwd()
    505          return normpath(path)
    506
    507  # realpath is a no-op on systems without islink support
    508  realpath = abspath
    509  # Win9x family and earlier have no Unicode filename support.
    510  supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
    511                                sys.getwindowsversion()[3] >= 2)
    512