posixpath

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

# Source Code for Module posixpath

      1  """Common operations on Posix pathnames.
      2
      3  Instead of importing this module directly, import os and refer to
      4  this module as os.path.  The "os.path" name is an alias for this
      5  module on Posix systems; on other systems (e.g. Mac, Windows),
      6  os.path provides the same operations in a manner specific to that
      7  platform, and is an alias to another module (e.g. macpath, ntpath).
      8
      9  Some of this can actually be useful on non-Posix systems too, e.g.
     10  for manipulation of the pathname component of URLs.
     11  """
     12
     13  import os
     14  import stat
     15  import genericpath
     16  import warnings
     17  from genericpath import *
     18
     19  __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
     20             "basename","dirname","commonprefix","getsize","getmtime",
     21             "getatime","getctime","islink","exists","lexists","isdir","isfile",
     22             "ismount","walk","expanduser","expandvars","normpath","abspath",
     23             "samefile","sameopenfile","samestat",
     24             "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
     25             "devnull","realpath","supports_unicode_filenames","relpath"]
     26
     27  # strings representing various path-related bits and pieces
     28  curdir = '.'
     29  pardir = '..'
     30  extsep = '.'
     31  sep = '/'
     32  pathsep = ':'
     33  defpath = ':/bin:/usr/bin'
     34  altsep = None
     35  devnull = '/dev/null'
     36
     37  # Normalize the case of a pathname.  Trivial in Posix, string.lower on Mac.
     38  # On MS-DOS this may also turn slashes into backslashes; however, other
     39  # normalizations (such as optimizing '../' away) are not allowed
     40  # (another function should be defined to do that).
     41
     42 -def normcase(s):
     43      """Normalize case of pathname.  Has no effect under Posix"""
     44      return s
     45
     46
     47  # Return whether a path is absolute.
     48  # Trivial in Posix, harder on the Mac or MS-DOS.
     49
     50 -def isabs(s):
     51      """Test whether a path is absolute"""
     52      return s.startswith('/')
     53
     54
     55  # Join pathnames.
     56  # Ignore the previous parts if a part is absolute.
     57  # Insert a '/' unless the first part is empty or already ends in '/'.
     58
     59 -def join(a, *p):
     60      """Join two or more pathname components, inserting '/' as needed.
     61      If any component is an absolute path, all previous path components
     62      will be discarded."""
     63      path = a
     64      for b in p:
     65          if b.startswith('/'):
     66              path = b
     67          elif path == '' or path.endswith('/'):
     68              path +=  b
     69          else:
     70              path += '/' + b
     71      return path
     72
     73
     74  # Split a path in head (everything up to the last '/') and tail (the
     75  # rest).  If the path ends in '/', tail will be empty.  If there is no
     76  # '/' in the path, head  will be empty.
     77  # Trailing '/'es are stripped from head unless it is the root.
     78
     79 -def split(p):
     80      """Split a pathname.  Returns tuple "(head, tail)" where "tail" is
     81      everything after the final slash.  Either part may be empty."""
     82      i = p.rfind('/') + 1
     83      head, tail = p[:i], p[i:]
     84      if head and head != '/'*len(head):
     85          head = head.rstrip('/')
     86      return head, tail
     87
     88
     89  # Split a path in root and extension.
     90  # The extension is everything starting at the last dot in the last
     91  # pathname component; the root is everything before that.
     92  # It is always true that root + ext == p.
     93
     94 -def splitext(p):
     95      return genericpath._splitext(p, sep, altsep, extsep)
     96  splitext.__doc__ = genericpath._splitext.__doc__
     97
     98  # Split a pathname into a drive specification and the rest of the
     99  # path.  Useful on DOS/Windows/NT; on Unix, the drive is always empty.
    100
    101 -def splitdrive(p):
    102      """Split a pathname into drive and path. On Posix, drive is always
    103      empty."""
    104      return '', p
    105
    106
    107  # Return the tail (basename) part of a path, same as split(path)[1].
    108
    109 -def basename(p):
    110      """Returns the final component of a pathname"""
    111      i = p.rfind('/') + 1
    112      return p[i:]
    113
    114
    115  # Return the head (dirname) part of a path, same as split(path)[0].
    116
    117 -def dirname(p):
    118      """Returns the directory component of a pathname"""
    119      i = p.rfind('/') + 1
    120      head = p[:i]
    121      if head and head != '/'*len(head):
    122          head = head.rstrip('/')
    123      return head
    124
    125
    126  # Is a path a symbolic link?
    127  # This will always return false on systems where os.lstat doesn't exist.
    128
    129 -def islink(path):
    130      """Test whether a path is a symbolic link"""
    131      try:
    132          st = os.lstat(path)
    133      except (os.error, AttributeError):
    134          return False
    135      return stat.S_ISLNK(st.st_mode)
    136
    137  # Being true for dangling symbolic links is also useful.
    138
    139 -def lexists(path):
    140      """Test whether a path exists.  Returns True for broken symbolic links"""
    141      try:
    142          st = os.lstat(path)
    143      except os.error:
    144          return False
    145      return True
    146
    147
    148  # Are two filenames really pointing to the same file?
    149
    150 -def samefile(f1, f2):
    151      """Test whether two pathnames reference the same actual file"""
    152      s1 = os.stat(f1)
    153      s2 = os.stat(f2)
    154      return samestat(s1, s2)
    155
    156
    157  # Are two open files really referencing the same file?
    158  # (Not necessarily the same file descriptor!)
    159
    160 -def sameopenfile(fp1, fp2):
    161      """Test whether two open file objects reference the same file"""
    162      s1 = os.fstat(fp1)
    163      s2 = os.fstat(fp2)
    164      return samestat(s1, s2)
    165
    166
    167  # Are two stat buffers (obtained from stat, fstat or lstat)
    168  # describing the same file?
    169
    170 -def samestat(s1, s2):
    171      """Test whether two stat buffers reference the same file"""
    172      return s1.st_ino == s2.st_ino and \
    173             s1.st_dev == s2.st_dev
    174
    175
    176  # Is a path a mount point?
    177  # (Does this work for all UNIXes?  Is it even guaranteed to work by Posix?)
    178
    179 -def ismount(path):
    180      """Test whether a path is a mount point"""
    181      try:
    182          s1 = os.lstat(path)
    183          s2 = os.lstat(join(path, '..'))
    184      except os.error:
    185          return False # It doesn't exist -- so not a mount point :-)
    186      dev1 = s1.st_dev
    187      dev2 = s2.st_dev
    188      if dev1 != dev2:
    189          return True     # path/.. on a different device as path
    190      ino1 = s1.st_ino
    191      ino2 = s2.st_ino
    192      if ino1 == ino2:
    193          return True     # path/.. is the same i-node as path
    194      return False
    195
    196
    197  # Directory tree walk.
    198  # For each directory under top (including top itself, but excluding
    199  # '.' and '..'), func(arg, dirname, filenames) is called, where
    200  # dirname is the name of the directory and filenames is the list
    201  # of files (and subdirectories etc.) in the directory.
    202  # The func may modify the filenames list, to implement a filter,
    203  # or to impose a different order of visiting.
    204
    205 -def walk(top, func, arg):
    206      """Directory tree walk with callback function.
    207
    208      For each directory in the directory tree rooted at top (including top
    209      itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
    210      dirname is the name of the directory, and fnames a list of the names of
    211      the files and subdirectories in dirname (excluding '.' and '..').  func
    212      may modify the fnames list in-place (e.g. via del or slice assignment),
    213      and walk will only recurse into the subdirectories whose names remain in
    214      fnames; this can be used to implement a filter, or to impose a specific
    215      order of visiting.  No semantics are defined for, or required of, arg,
    216      beyond that arg is always passed to func.  It can be used, e.g., to pass
    217      a filename pattern, or a mutable object designed to accumulate
    218      statistics.  Passing None for arg is common."""
    219      warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",
    220                        stacklevel=2)
    221      try:
    222          names = os.listdir(top)
    223      except os.error:
    224          return
    225      func(arg, top, names)
    226      for name in names:
    227          name = join(top, name)
    228          try:
    229              st = os.lstat(name)
    230          except os.error:
    231              continue
    232          if stat.S_ISDIR(st.st_mode):
    233              walk(name, func, arg)
    234
    235
    236  # Expand paths beginning with '~' or '~user'.
    237  # '~' means $HOME; '~user' means that user's home directory.
    238  # If the path doesn't begin with '~', or if the user or $HOME is unknown,
    239  # the path is returned unchanged (leaving error reporting to whatever
    240  # function is called with the expanded path as argument).
    241  # See also module 'glob' for expansion of *, ? and [...] in pathnames.
    242  # (A function should also be defined to do full *sh-style environment
    243  # variable expansion.)
    244
    245 -def expanduser(path):
    246      """Expand ~ and ~user constructions.  If user or $HOME is unknown,
    247      do nothing."""
    248      if not path.startswith('~'):
    249          return path
    250      i = path.find('/', 1)
    251      if i < 0:
    252          i = len(path)
    253      if i == 1:
    254          if 'HOME' not in os.environ:
    255              import pwd
    256              userhome = pwd.getpwuid(os.getuid()).pw_dir
    257          else:
    258              userhome = os.environ['HOME']
    259      else:
    260          import pwd
    261          try:
    262              pwent = pwd.getpwnam(path[1:i])
    263          except KeyError:
    264              return path
    265          userhome = pwent.pw_dir
    266      userhome = userhome.rstrip('/') or userhome
    267      return userhome + path[i:]
    268
    269
    270  # Expand paths containing shell variable substitutions.
    271  # This expands the forms $variable and ${variable} only.
    272  # Non-existent variables are left unchanged.
    273
    274  _varprog = None
    275
    276 -def expandvars(path):
    277      """Expand shell variables of form $var and ${var}.  Unknown variables
    278      are left unchanged."""
    279      global _varprog
    280      if '$' not in path:
    281          return path
    282      if not _varprog:
    283          import re
    284          _varprog = re.compile(r'\$(\w+|\{[^}]*\})')
    285      i = 0
    286      while True:
    287          m = _varprog.search(path, i)
    288          if not m:
    289              break
    290          i, j = m.span(0)
    291          name = m.group(1)
    292          if name.startswith('{') and name.endswith('}'):
    293              name = name[1:-1]
    294          if name in os.environ:
    295              tail = path[j:]
    296              path = path[:i] + os.environ[name]
    297              i = len(path)
    298              path += tail
    299          else:
    300              i = j
    301      return path
    302
    303
    304  # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
    305  # It should be understood that this may change the meaning of the path
    306  # if it contains symbolic links!
    307
    308 -def normpath(path):
    309      """Normalize path, eliminating double slashes, etc."""
    310      # Preserve unicode (if path is unicode)
    311      slash, dot = (u'/', u'.') if isinstance(path, unicode) else ('/', '.')
    312      if path == '':
    313          return dot
    314      initial_slashes = path.startswith('/')
    315      # POSIX allows one or two initial slashes, but treats three or more
    316      # as single slash.
    317      if (initial_slashes and
    318          path.startswith('//') and not path.startswith('///')):
    319          initial_slashes = 2
    320      comps = path.split('/')
    321      new_comps = []
    322      for comp in comps:
    323          if comp in ('', '.'):
    324              continue
    325          if (comp != '..' or (not initial_slashes and not new_comps) or
    326               (new_comps and new_comps[-1] == '..')):
    327              new_comps.append(comp)
    328          elif new_comps:
    329              new_comps.pop()
    330      comps = new_comps
    331      path = slash.join(comps)
    332      if initial_slashes:
    333          path = slash*initial_slashes + path
    334      return path or dot
    335
    336
    337 -def abspath(path):
    338      """Return an absolute path."""
    339      if not isabs(path):
    340          if isinstance(path, unicode):
    341              cwd = os.getcwdu()
    342          else:
    343              cwd = os.getcwd()
    344          path = join(cwd, path)
    345      return normpath(path)
    346
    347
    348  # Return a canonical path (i.e. the absolute location of a file on the
    349  # filesystem).
    350
    351 -def realpath(filename):
    352      """Return the canonical path of the specified filename, eliminating any
    353  symbolic links encountered in the path."""
    354      if isabs(filename):
    355          bits = ['/'] + filename.split('/')[1:]
    356      else:
    357          bits = [''] + filename.split('/')
    358
    359      for i in range(2, len(bits)+1):
    360          component = join(*bits[0:i])
    361          # Resolve symbolic links.
    362          if islink(component):
    363              resolved = _resolve_link(component)
    364              if resolved is None:
    365                  # Infinite loop -- return original component + rest of the path
    366                  return abspath(join(*([component] + bits[i:])))
    367              else:
    368                  newpath = join(*([resolved] + bits[i:]))
    369                  return realpath(newpath)
    370
    371      return abspath(filename)
    372
    373
    374 -def _resolve_link(path):
    375      """Internal helper function.  Takes a path and follows symlinks
    376      until we either arrive at something that isn't a symlink, or
    377      encounter a path we've seen before (meaning that there's a loop).
    378      """
    379      paths_seen = []
    380      while islink(path):
    381          if path in paths_seen:
    382              # Already seen this path, so we must have a symlink loop
    383              return None
    384          paths_seen.append(path)
    385          # Resolve where the link points to
    386          resolved = os.readlink(path)
    387          if not isabs(resolved):
    388              dir = dirname(path)
    389              path = normpath(join(dir, resolved))
    390          else:
    391              path = normpath(resolved)
    392      return path
    393
    394  supports_unicode_filenames = False
    395
    396 -def relpath(path, start=curdir):
    397      """Return a relative version of a path"""
    398
    399      if not path:
    400          raise ValueError("no path specified")
    401
    402      start_list = abspath(start).split(sep)
    403      path_list = abspath(path).split(sep)
    404
    405      # Work out how much of the filepath is shared by start and path.
    406      i = len(commonprefix([start_list, path_list]))
    407
    408      rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
    409      if not rel_list:
    410          return curdir
    411      return join(*rel_list)
    412