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 sys 
 15  import stat 
 16  import genericpath 
 17  import warnings 
 18  from genericpath import * 
 19   
 20  __all__ = ["normcase","isabs","join","splitdrive","split","splitext", 
 21             "basename","dirname","commonprefix","getsize","getmtime", 
 22             "getatime","getctime","islink","exists","lexists","isdir","isfile", 
 23             "ismount","walk","expanduser","expandvars","normpath","abspath", 
 24             "samefile","sameopenfile","samestat", 
 25             "curdir","pardir","sep","pathsep","defpath","altsep","extsep", 
 26             "devnull","realpath","supports_unicode_filenames","relpath"] 
 27   
 28   
 29  curdir = '.' 
 30  pardir = '..' 
 31  extsep = '.' 
 32  sep = '/' 
 33  pathsep = ':' 
 34  defpath = ':/bin:/usr/bin' 
 35  altsep = None 
 36  devnull = '/dev/null' 
 37   
 38   
 39   
 40   
 41   
 42   
 44      """Normalize case of pathname.  Has no effect under Posix""" 
 45      return s 
  46   
 47   
 48   
 49   
 50   
 52      """Test whether a path is absolute""" 
 53      return s.startswith('/') 
  54   
 55   
 56   
 57   
 58   
 59   
 61      """Join two or more pathname components, inserting '/' as needed. 
 62      If any component is an absolute path, all previous path components 
 63      will be discarded.""" 
 64      path = a 
 65      for b in p: 
 66          if b.startswith('/'): 
 67              path = b 
 68          elif path == '' or path.endswith('/'): 
 69              path +=  b 
 70          else: 
 71              path += '/' + b 
 72      return path 
  73   
 74   
 75   
 76   
 77   
 78   
 79   
 81      """Split a pathname.  Returns tuple "(head, tail)" where "tail" is 
 82      everything after the final slash.  Either part may be empty.""" 
 83      i = p.rfind('/') + 1 
 84      head, tail = p[:i], p[i:] 
 85      if head and head != '/'*len(head): 
 86          head = head.rstrip('/') 
 87      return head, tail 
  88   
 89   
 90   
 91   
 92   
 93   
 94   
 96      return genericpath._splitext(p, sep, altsep, extsep) 
  97  splitext.__doc__ = genericpath._splitext.__doc__ 
 98   
 99   
100   
101   
103      """Split a pathname into drive and path. On Posix, drive is always 
104      empty.""" 
105      return '', p 
 106   
107   
108   
109   
111      """Returns the final component of a pathname""" 
112      i = p.rfind('/') + 1 
113      return p[i:] 
 114   
115   
116   
117   
119      """Returns the directory component of a pathname""" 
120      i = p.rfind('/') + 1 
121      head = p[:i] 
122      if head and head != '/'*len(head): 
123          head = head.rstrip('/') 
124      return head 
 125   
126   
127   
128   
129   
131      """Test whether a path is a symbolic link""" 
132      try: 
133          st = os.lstat(path) 
134      except (os.error, AttributeError): 
135          return False 
136      return stat.S_ISLNK(st.st_mode) 
 137   
138   
139   
141      """Test whether a path exists.  Returns True for broken symbolic links""" 
142      try: 
143          os.lstat(path) 
144      except os.error: 
145          return False 
146      return True 
 147   
148   
149   
150   
152      """Test whether two pathnames reference the same actual file""" 
153      s1 = os.stat(f1) 
154      s2 = os.stat(f2) 
155      return samestat(s1, s2) 
 156   
157   
158   
159   
160   
162      """Test whether two open file objects reference the same file""" 
163      s1 = os.fstat(fp1) 
164      s2 = os.fstat(fp2) 
165      return samestat(s1, s2) 
 166   
167   
168   
169   
170   
172      """Test whether two stat buffers reference the same file""" 
173      return s1.st_ino == s2.st_ino and \ 
174             s1.st_dev == s2.st_dev 
 175   
176   
177   
178   
179   
181      """Test whether a path is a mount point""" 
182      if islink(path): 
183           
184          return False 
185      try: 
186          s1 = os.lstat(path) 
187          s2 = os.lstat(join(path, '..')) 
188      except os.error: 
189          return False  
190      dev1 = s1.st_dev 
191      dev2 = s2.st_dev 
192      if dev1 != dev2: 
193          return True      
194      ino1 = s1.st_ino 
195      ino2 = s2.st_ino 
196      if ino1 == ino2: 
197          return True      
198      return False 
 199   
200   
201   
202   
203   
204   
205   
206   
207   
208   
209 -def walk(top, func, arg): 
 210      """Directory tree walk with callback function. 
211   
212      For each directory in the directory tree rooted at top (including top 
213      itself, but excluding '.' and '..'), call func(arg, dirname, fnames). 
214      dirname is the name of the directory, and fnames a list of the names of 
215      the files and subdirectories in dirname (excluding '.' and '..').  func 
216      may modify the fnames list in-place (e.g. via del or slice assignment), 
217      and walk will only recurse into the subdirectories whose names remain in 
218      fnames; this can be used to implement a filter, or to impose a specific 
219      order of visiting.  No semantics are defined for, or required of, arg, 
220      beyond that arg is always passed to func.  It can be used, e.g., to pass 
221      a filename pattern, or a mutable object designed to accumulate 
222      statistics.  Passing None for arg is common.""" 
223      warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.", 
224                        stacklevel=2) 
225      try: 
226          names = os.listdir(top) 
227      except os.error: 
228          return 
229      func(arg, top, names) 
230      for name in names: 
231          name = join(top, name) 
232          try: 
233              st = os.lstat(name) 
234          except os.error: 
235              continue 
236          if stat.S_ISDIR(st.st_mode): 
237              walk(name, func, arg) 
 238   
239   
240   
241   
242   
243   
244   
245   
246   
247   
248   
250      """Expand ~ and ~user constructions.  If user or $HOME is unknown, 
251      do nothing.""" 
252      if not path.startswith('~'): 
253          return path 
254      i = path.find('/', 1) 
255      if i < 0: 
256          i = len(path) 
257      if i == 1: 
258          if 'HOME' not in os.environ: 
259              import pwd 
260              userhome = pwd.getpwuid(os.getuid()).pw_dir 
261          else: 
262              userhome = os.environ['HOME'] 
263      else: 
264          import pwd 
265          try: 
266              pwent = pwd.getpwnam(path[1:i]) 
267          except KeyError: 
268              return path 
269          userhome = pwent.pw_dir 
270      userhome = userhome.rstrip('/') or userhome 
271      return userhome + path[i:] 
 272   
273   
274   
275   
276   
277   
278  _varprog = None 
279   
306   
307   
308   
309   
310   
311   
313      """Normalize path, eliminating double slashes, etc.""" 
314       
315      slash, dot = (u'/', u'.') if isinstance(path, unicode) else ('/', '.') 
316      if path == '': 
317          return dot 
318      initial_slashes = path.startswith('/') 
319       
320       
321      if (initial_slashes and 
322          path.startswith('//') and not path.startswith('///')): 
323          initial_slashes = 2 
324      comps = path.split('/') 
325      new_comps = [] 
326      for comp in comps: 
327          if comp in ('', '.'): 
328              continue 
329          if (comp != '..' or (not initial_slashes and not new_comps) or 
330               (new_comps and new_comps[-1] == '..')): 
331              new_comps.append(comp) 
332          elif new_comps: 
333              new_comps.pop() 
334      comps = new_comps 
335      path = slash.join(comps) 
336      if initial_slashes: 
337          path = slash*initial_slashes + path 
338      return path or dot 
 339   
340   
342      """Return an absolute path.""" 
343      if not isabs(path): 
344          if isinstance(path, unicode): 
345              cwd = os.getcwdu() 
346          else: 
347              cwd = os.getcwd() 
348          path = join(cwd, path) 
349      return normpath(path) 
 350   
351   
352   
353   
354   
356      """Return the canonical path of the specified filename, eliminating any 
357  symbolic links encountered in the path.""" 
358      if isabs(filename): 
359          bits = ['/'] + filename.split('/')[1:] 
360      else: 
361          bits = [''] + filename.split('/') 
362   
363      for i in range(2, len(bits)+1): 
364          component = join(*bits[0:i]) 
365           
366          if islink(component): 
367              resolved = _resolve_link(component) 
368              if resolved is None: 
369                   
370                  return abspath(join(*([component] + bits[i:]))) 
371              else: 
372                  newpath = join(*([resolved] + bits[i:])) 
373                  return realpath(newpath) 
374   
375      return abspath(filename) 
 376   
377   
379      """Internal helper function.  Takes a path and follows symlinks 
380      until we either arrive at something that isn't a symlink, or 
381      encounter a path we've seen before (meaning that there's a loop). 
382      """ 
383      paths_seen = set() 
384      while islink(path): 
385          if path in paths_seen: 
386               
387              return None 
388          paths_seen.add(path) 
389           
390          resolved = os.readlink(path) 
391          if not isabs(resolved): 
392              dir = dirname(path) 
393              path = normpath(join(dir, resolved)) 
394          else: 
395              path = normpath(resolved) 
396      return path 
 397   
398  supports_unicode_filenames = (sys.platform == 'darwin') 
399   
401      """Return a relative version of a path""" 
402   
403      if not path: 
404          raise ValueError("no path specified") 
405   
406      start_list = [x for x in abspath(start).split(sep) if x] 
407      path_list = [x for x in abspath(path).split(sep) if x] 
408   
409       
410      i = len(commonprefix([start_list, path_list])) 
411   
412      rel_list = [pardir] * (len(start_list)-i) + path_list[i:] 
413      if not rel_list: 
414          return curdir 
415      return join(*rel_list) 
 416