Home | History | Annotate | Download | only in Lib
      1 """Pathname and path-related operations for the Macintosh."""
      2 
      3 import os
      4 import warnings
      5 from stat import *
      6 import genericpath
      7 from genericpath import *
      8 from genericpath import _unicode
      9 
     10 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
     11            "basename","dirname","commonprefix","getsize","getmtime",
     12            "getatime","getctime", "islink","exists","lexists","isdir","isfile",
     13            "walk","expanduser","expandvars","normpath","abspath",
     14            "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
     15            "devnull","realpath","supports_unicode_filenames"]
     16 
     17 # strings representing various path-related bits and pieces
     18 curdir = ':'
     19 pardir = '::'
     20 extsep = '.'
     21 sep = ':'
     22 pathsep = '\n'
     23 defpath = ':'
     24 altsep = None
     25 devnull = 'Dev:Null'
     26 
     27 # Normalize the case of a pathname.  Dummy in Posix, but <s>.lower() here.
     28 
     29 def normcase(path):
     30     return path.lower()
     31 
     32 
     33 def isabs(s):
     34     """Return true if a path is absolute.
     35     On the Mac, relative paths begin with a colon,
     36     but as a special case, paths with no colons at all are also relative.
     37     Anything else is absolute (the string up to the first colon is the
     38     volume name)."""
     39 
     40     return ':' in s and s[0] != ':'
     41 
     42 
     43 def join(s, *p):
     44     path = s
     45     for t in p:
     46         if (not path) or isabs(t):
     47             path = t
     48             continue
     49         if t[:1] == ':':
     50             t = t[1:]
     51         if ':' not in path:
     52             path = ':' + path
     53         if path[-1:] != ':':
     54             path = path + ':'
     55         path = path + t
     56     return path
     57 
     58 
     59 def split(s):
     60     """Split a pathname into two parts: the directory leading up to the final
     61     bit, and the basename (the filename, without colons, in that directory).
     62     The result (s, t) is such that join(s, t) yields the original argument."""
     63 
     64     if ':' not in s: return '', s
     65     colon = 0
     66     for i in range(len(s)):
     67         if s[i] == ':': colon = i + 1
     68     path, file = s[:colon-1], s[colon:]
     69     if path and not ':' in path:
     70         path = path + ':'
     71     return path, file
     72 
     73 
     74 def splitext(p):
     75     return genericpath._splitext(p, sep, altsep, extsep)
     76 splitext.__doc__ = genericpath._splitext.__doc__
     77 
     78 def splitdrive(p):
     79     """Split a pathname into a drive specification and the rest of the
     80     path.  Useful on DOS/Windows/NT; on the Mac, the drive is always
     81     empty (don't use the volume name -- it doesn't have the same
     82     syntactic and semantic oddities as DOS drive letters, such as there
     83     being a separate current directory per drive)."""
     84 
     85     return '', p
     86 
     87 
     88 # Short interfaces to split()
     89 
     90 def dirname(s): return split(s)[0]
     91 def basename(s): return split(s)[1]
     92 
     93 def ismount(s):
     94     if not isabs(s):
     95         return False
     96     components = split(s)
     97     return len(components) == 2 and components[1] == ''
     98 
     99 def islink(s):
    100     """Return true if the pathname refers to a symbolic link."""
    101 
    102     try:
    103         import Carbon.File
    104         return Carbon.File.ResolveAliasFile(s, 0)[2]
    105     except:
    106         return False
    107 
    108 # Is `stat`/`lstat` a meaningful difference on the Mac?  This is safe in any
    109 # case.
    110 
    111 def lexists(path):
    112     """Test whether a path exists.  Returns True for broken symbolic links"""
    113 
    114     try:
    115         st = os.lstat(path)
    116     except os.error:
    117         return False
    118     return True
    119 
    120 def expandvars(path):
    121     """Dummy to retain interface-compatibility with other operating systems."""
    122     return path
    123 
    124 
    125 def expanduser(path):
    126     """Dummy to retain interface-compatibility with other operating systems."""
    127     return path
    128 
    129 class norm_error(Exception):
    130     """Path cannot be normalized"""
    131 
    132 def normpath(s):
    133     """Normalize a pathname.  Will return the same result for
    134     equivalent paths."""
    135 
    136     if ":" not in s:
    137         return ":"+s
    138 
    139     comps = s.split(":")
    140     i = 1
    141     while i < len(comps)-1:
    142         if comps[i] == "" and comps[i-1] != "":
    143             if i > 1:
    144                 del comps[i-1:i+1]
    145                 i = i - 1
    146             else:
    147                 # best way to handle this is to raise an exception
    148                 raise norm_error, 'Cannot use :: immediately after volume name'
    149         else:
    150             i = i + 1
    151 
    152     s = ":".join(comps)
    153 
    154     # remove trailing ":" except for ":" and "Volume:"
    155     if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
    156         s = s[:-1]
    157     return s
    158 
    159 
    160 def walk(top, func, arg):
    161     """Directory tree walk with callback function.
    162 
    163     For each directory in the directory tree rooted at top (including top
    164     itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
    165     dirname is the name of the directory, and fnames a list of the names of
    166     the files and subdirectories in dirname (excluding '.' and '..').  func
    167     may modify the fnames list in-place (e.g. via del or slice assignment),
    168     and walk will only recurse into the subdirectories whose names remain in
    169     fnames; this can be used to implement a filter, or to impose a specific
    170     order of visiting.  No semantics are defined for, or required of, arg,
    171     beyond that arg is always passed to func.  It can be used, e.g., to pass
    172     a filename pattern, or a mutable object designed to accumulate
    173     statistics.  Passing None for arg is common."""
    174     warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",
    175                       stacklevel=2)
    176     try:
    177         names = os.listdir(top)
    178     except os.error:
    179         return
    180     func(arg, top, names)
    181     for name in names:
    182         name = join(top, name)
    183         if isdir(name) and not islink(name):
    184             walk(name, func, arg)
    185 
    186 
    187 def abspath(path):
    188     """Return an absolute path."""
    189     if not isabs(path):
    190         if isinstance(path, _unicode):
    191             cwd = os.getcwdu()
    192         else:
    193             cwd = os.getcwd()
    194         path = join(cwd, path)
    195     return normpath(path)
    196 
    197 # realpath is a no-op on systems without islink support
    198 def realpath(path):
    199     path = abspath(path)
    200     try:
    201         import Carbon.File
    202     except ImportError:
    203         return path
    204     if not path:
    205         return path
    206     components = path.split(':')
    207     path = components[0] + ':'
    208     for c in components[1:]:
    209         path = join(path, c)
    210         try:
    211             path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname()
    212         except Carbon.File.Error:
    213             pass
    214     return path
    215 
    216 supports_unicode_filenames = True
    217