skip to navigation
skip to content

   1 
   2 # -*- coding: iso-8859-1 -*-
   3 """ path.py - An object representing a path to a file or directory.
   4 
   5 Example:
   6 
   7 from path import path
   8 d = path('/home/guido/bin')
   9 for f in d.files('*.py'):
  10     f.chmod(0755)
  11 
  12 This module requires Python 2.2 or later.
  13 
  14 
  15 URL:     http://www.jorendorff.com/articles/python/path
  16 Author:  Jason Orendorff <jason@jorendorff.com> (and others - see the url!)
  17 Date:    7 Mar 2004
  18 
  19 Adapted for stdlib by: Reinhold Birkenfeld, July 2005
  20 Modified by Björn Lindqvist <bjourne@gmail.com>, January 2006
  21 """
  22 
  23 # TODO
  24 #   - Better error message in listdir() when self isn't a
  25 #     directory. (On Windows, the error message really sucks.)
  26 #   - Make sure everything has a good docstring.
  27 #   - Add methods for regex find and replace.
  28 #   - Perhaps support arguments to touch().
  29 #   - Could add split() and join() methods that generate warnings.
  30 #   - Note:  __add__() technically has a bug, I think, where
  31 #     it doesn't play nice with other types that implement
  32 #     __radd__().  Test this.
  33 
  34 import fnmatch
  35 import glob
  36 import os
  37 import shutil
  38 import sys
  39 
  40 __all__ = ['path']
  41 __version__ = '2.0.4'
  42 
  43 # Universal newline support
  44 _textmode = 'r'
  45 if hasattr(file, 'newlines'):
  46     _textmode = 'U'
  47 
  48 # Use unicode strings if possible
  49 _base = str
  50 if os.path.supports_unicode_filenames:
  51     _base = unicode
  52 
  53 
  54 class path(_base):
  55     """ Represents a filesystem path.
  56 
  57     For documentation on individual methods, consult their
  58     counterparts in os.path.
  59     """
  60 
  61     # --- Special Python methods.
  62     def __new__(typ, *args):
  63         """
  64         Creates a new path object concatenating the *args.  *args
  65         may only contain Path objects or strings.  If *args is
  66         empty, Path(os.curdir) is created.
  67         """
  68         if not args:
  69             return typ(os.curdir)
  70         for arg in args:
  71             if not isinstance(arg, basestring):
  72                 raise ValueError("%s() arguments must be Path, str or "
  73                                  "unicode" % typ.__name__)
  74         if len(args) == 1:
  75             return _base.__new__(typ, *args)
  76         return typ(os.path.join(*args))
  77 
  78     def __repr__(self):
  79         return '%s(%r)' % (self.__class__.__name__, _base(self))
  80 
  81     # Adding a path and a string yields a path.
  82     def __add__(self, more):
  83         return self.__class__(_base(self) + more)
  84 
  85     def __radd__(self, other):
  86         return self.__class__(other + _base(self))
  87 
  88     @classmethod
  89     def cwd(cls):
  90         """ Return the current working directory as a path object. """
  91         return path(os.getcwd())
  92 
  93     # --- Operations on path strings.
  94 
  95     def abspath(self):
  96         return self.__class__(os.path.abspath(self))
  97 
  98     def normcase(self):
  99         return self.__class__(os.path.normcase(self))
 100 
 101     def normpath(self):
 102         return self.__class__(os.path.normpath(self))
 103 
 104     def realpath(self):
 105         return self.__class__(os.path.realpath(self))
 106 
 107     def expanduser(self):
 108         return self.__class__(os.path.expanduser(self))
 109 
 110     def expandvars(self):
 111         return self.__class__(os.path.expandvars(self))
 112 
 113     def expand(self):
 114         """ Clean up a filename by calling expandvars(),
 115         expanduser(), and normpath() on it.
 116 
 117         This is commonly everything needed to clean up a filename
 118         read from a configuration file, for example.
 119         """
 120         return self.expandvars().expanduser().normpath()
 121 
 122     def _get_namebase(self):
 123         base, ext = os.path.splitext(self.name)
 124         return base
 125 
 126     def _get_ext(self):
 127         f, ext = os.path.splitext(_base(self))
 128         return ext
 129 
 130     def _get_drive(self):
 131         drive, r = os.path.splitdrive(self)
 132         return self.__class__(drive)
 133 
 134     def _get_dirname(self):
 135         return self.__class__(os.path.dirname(self))
 136 
 137     parent = property(
 138         _get_dirname, None, None,
 139         """ This path's parent directory, as a new path object.
 140 
 141         For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
 142         """)
 143 
 144     name = property(
 145         os.path.basename, None, None,
 146         """ The name of this file or directory without the full path.
 147 
 148         For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
 149         """)
 150 
 151     namebase = property(
 152         _get_namebase, None, None,
 153         """ The same as path.name, but with one file extension stripped off.
 154 
 155         For example, path('/home/guido/python.tar.gz').name     == 'python.tar.gz',
 156         but          path('/home/guido/python.tar.gz').namebase == 'python.tar'
 157         """)
 158 
 159     ext = property(
 160         _get_ext, None, None,
 161         """ The file extension, for example '.py'. """)
 162 
 163     drive = property(
 164         _get_drive, None, None,
 165         """ The drive specifier, for example 'C:'.
 166         This is always empty on systems that don't use drive specifiers.
 167         """)
 168 
 169     def splitpath(self):
 170         """ p.splitpath() -> Return (p.parent, p.name). """
 171         parent, child = os.path.split(self)
 172         return self.__class__(parent), child
 173 
 174     def stripext(self):
 175         """ p.stripext() -> Remove one file extension from the path.
 176 
 177         For example, path('/home/guido/python.tar.gz').stripext()
 178         returns path('/home/guido/python.tar').
 179         """
 180         return path(os.path.splitext(self)[0])
 181 
 182     if hasattr(os.path, 'splitunc'):
 183         def splitunc(self):
 184             unc, rest = os.path.splitunc(self)
 185             return self.__class__(unc), rest
 186 
 187         def _get_uncshare(self):
 188             unc, r = os.path.splitunc(self)
 189             return self.__class__(unc)
 190 
 191         uncshare = property(
 192             _get_uncshare, None, None,
 193             """ The UNC mount point for this path.
 194             This is empty for paths on local drives. """)
 195 
 196     def splitall(self):
 197         """ Return a list of the path components in this path.
 198 
 199         The first item in the list will be a path.  Its value will be
 200         either os.curdir, os.pardir, empty, or the root directory of
 201         this path (for example, '/' or 'C:\\').  The other items in
 202         the list will be strings.
 203 
 204         path.path(*result) will yield the original path.
 205         """
 206         parts = []
 207         loc = self
 208         while loc != os.curdir and loc != os.pardir:
 209             prev = loc
 210             loc, child = prev.splitpath()
 211             loc = self.__class__(loc)
 212             if loc == prev:
 213                 break
 214             parts.append(child)
 215         parts.append(loc)
 216         parts.reverse()
 217         return parts
 218 
 219     def relpath(self):
 220         """ Return this path as a relative path,
 221         based from the current working directory.
 222         """
 223         return self.__class__.cwd().relpathto(self)
 224 
 225     def relpathto(self, dest):
 226         """ Return a relative path from self to dest.
 227 
 228         If there is no relative path from self to dest, for example if
 229         they reside on different drives in Windows, then this returns
 230         dest.abspath().
 231         """
 232         origin = self.abspath()
 233         dest = self.__class__(dest).abspath()
 234 
 235         orig_list = origin.normcase().splitall()
 236         # Don't normcase dest!  We want to preserve the case.
 237         dest_list = dest.splitall()
 238 
 239         if orig_list[0] != os.path.normcase(dest_list[0]):
 240             # Can't get here from there.
 241             return dest
 242 
 243         # Find the location where the two paths start to differ.
 244         i = 0
 245         for start_seg, dest_seg in zip(orig_list, dest_list):
 246             if start_seg != os.path.normcase(dest_seg):
 247                 break
 248             i += 1
 249 
 250         # Now i is the point where the two paths diverge.
 251         # Need a certain number of "os.pardir"s to work up
 252         # from the origin to the point of divergence.
 253         segments = [os.pardir] * (len(orig_list) - i)
 254         # Need to add the diverging part of dest_list.
 255         segments += dest_list[i:]
 256         if len(segments) == 0:
 257             # If they happen to be identical, use os.curdir.
 258             return self.__class__(os.curdir)
 259         else:
 260             return self.__class__(os.path.join(*segments))
 261 
 262 
 263     # --- Listing, searching, walking, and matching
 264 
 265     def listdir(self, pattern=None):
 266         """ D.listdir() -> List of items in this directory.
 267 
 268         Use D.files() or D.dirs() instead if you want a listing
 269         of just files or just subdirectories.
 270 
 271         The elements of the list are path objects.
 272 
 273         With the optional 'pattern' argument, this only lists
 274         items whose names match the given pattern.
 275         """
 276         names = os.listdir(self)
 277         if pattern is not None:
 278             names = fnmatch.filter(names, pattern)
 279         return [path(self, child) for child in names]
 280 
 281     def dirs(self, pattern=None):
 282         """ D.dirs() -> List of this directory's subdirectories.
 283 
 284         The elements of the list are path objects.
 285         This does not walk recursively into subdirectories
 286         (but see path.walkdirs).
 287 
 288         With the optional 'pattern' argument, this only lists
 289         directories whose names match the given pattern.  For
 290         example, d.dirs('build-*').
 291         """
 292         return [p for p in self.listdir(pattern) if p.isdir()]
 293 
 294     def files(self, pattern=None):
 295         """ D.files() -> List of the files in this directory.
 296 
 297         The elements of the list are path objects.
 298         This does not walk into subdirectories (see path.walkfiles).
 299 
 300         With the optional 'pattern' argument, this only lists files
 301         whose names match the given pattern.  For example,
 302         d.files('*.pyc').
 303         """
 304 
 305         return [p for p in self.listdir(pattern) if p.isfile()]
 306 
 307     def walk(self, pattern=None):
 308         """ D.walk() -> iterator over files and subdirs, recursively.
 309 
 310         The iterator yields path objects naming each child item of
 311         this directory and its descendants.  This requires that
 312         D.isdir().
 313 
 314         This performs a depth-first traversal of the directory tree.
 315         Each directory is returned just before all its children.
 316         """
 317         for child in self.listdir():
 318             if pattern is None or child.match(pattern):
 319                 yield child
 320             if child.isdir():
 321                 for item in child.walk(pattern):
 322                     yield item
 323 
 324     def walkdirs(self, pattern=None):
 325         """ D.walkdirs() -> iterator over subdirs, recursively.
 326 
 327         With the optional 'pattern' argument, this yields only
 328         directories whose names match the given pattern.  For
 329         example, mydir.walkdirs('*test') yields only directories
 330         with names ending in 'test'.
 331         """
 332         for child in self.dirs():
 333             if pattern is None or child.match(pattern):
 334                 yield child
 335             for subsubdir in child.walkdirs(pattern):
 336                 yield subsubdir
 337 
 338     def walkfiles(self, pattern=None):
 339         """ D.walkfiles() -> iterator over files in D, recursively.
 340 
 341         The optional argument, pattern, limits the results to files
 342         with names that match the pattern.  For example,
 343         mydir.walkfiles('*.tmp') yields only files with the .tmp
 344         extension.
 345         """
 346         for child in self.listdir():
 347             if child.isfile():
 348                 if pattern is None or child.match(pattern):
 349                     yield child
 350             elif child.isdir():
 351                 for f in child.walkfiles(pattern):
 352                     yield f
 353 
 354     def match(self, pattern):
 355         """ Return True if self.name matches the given pattern.
 356 
 357         pattern - A filename pattern with wildcards,
 358             for example '*.py'.
 359         """
 360         return fnmatch.fnmatch(self.name, pattern)
 361 
 362     def matchcase(self, pattern):
 363         """ Test whether the path matches pattern, returning true or
 364         false; the comparison is always case-sensitive.
 365         """
 366         return fnmatch.fnmatchcase(self.name, pattern)
 367 
 368     def glob(self, pattern):
 369         """ Return a list of path objects that match the pattern.
 370 
 371         pattern - a path relative to this directory, with wildcards.
 372 
 373         For example, path('/users').glob('*/bin/*') returns a list
 374         of all the files users have in their bin directories.
 375         """
 376         return map(path, glob.glob(_base(path(self, pattern))))
 377 
 378     # --- Methods for querying the filesystem.
 379 
 380     exists = os.path.exists
 381     isabs = os.path.isabs
 382     isdir = os.path.isdir
 383     isfile = os.path.isfile
 384     islink = os.path.islink
 385     ismount = os.path.ismount
 386 
 387     if hasattr(os.path, 'samefile'):
 388         samefile = os.path.samefile
 389 
 390     def atime(self):
 391         """Last access time of the file."""
 392         return os.path.getatime(self)
 393 
 394     def mtime(self):
 395         """Last-modified time of the file."""
 396         return os.path.getmtime(self)
 397 
 398     def ctime(self):
 399         """
 400         Return the system's ctime which, on some systems (like Unix)
 401         is the time of the last change, and, on others (like Windows),
 402         is the creation time for path.
 403 
 404         The return value is a number giving the number of seconds
 405         since the epoch (see the time module). Raise os.error if the
 406         file does not exist or is inaccessible.
 407         """
 408         return os.path.getctime(self)
 409 
 410     def size(self):
 411         """Size of the file, in bytes."""
 412         return os.path.getsize(self)
 413 
 414     if hasattr(os, 'access'):
 415         def access(self, mode):
 416             """ Return true if current user has access to this path.
 417 
 418             mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
 419             """
 420             return os.access(self, mode)
 421 
 422     def stat(self):
 423         """ Perform a stat() system call on this path. """
 424         return os.stat(self)
 425 
 426     def lstat(self):
 427         """ Like path.stat(), but do not follow symbolic links. """
 428         return os.lstat(self)
 429 
 430     if hasattr(os, 'statvfs'):
 431         def statvfs(self):
 432             """ Perform a statvfs() system call on this path. """
 433             return os.statvfs(self)
 434 
 435     if hasattr(os, 'pathconf'):
 436         def pathconf(self, name):
 437             return os.pathconf(self, name)
 438 
 439 
 440     # --- Modifying operations on files and directories
 441 
 442     def utime(self, times):
 443         """ Set the access and modified times of this file. """
 444         os.utime(self, times)
 445 
 446     def chmod(self, mode):
 447         os.chmod(self, mode)
 448 
 449     if hasattr(os, 'chown'):
 450         def chown(self, uid, gid):
 451             os.chown(self, uid, gid)
 452 
 453     def rename(self, new):
 454         os.rename(self, new)
 455 
 456     def renames(self, new):
 457         os.renames(self, new)
 458 
 459 
 460     # --- Create/delete operations on directories
 461 
 462     def mkdir(self, mode=0777):
 463         os.mkdir(self, mode)
 464 
 465     def makedirs(self, mode=0777):
 466         os.makedirs(self, mode)
 467 
 468     def rmdir(self):
 469         os.rmdir(self)
 470 
 471     def removedirs(self):
 472         os.removedirs(self)
 473 
 474 
 475     # --- Modifying operations on files
 476 
 477     def touch(self):
 478         """ Set the access/modified times of this file to the current time.
 479         Create the file if it does not exist.
 480         """
 481         fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666)
 482         os.close(fd)
 483         os.utime(self, None)
 484 
 485     def remove(self):
 486         os.remove(self)
 487 
 488     def unlink(self):
 489         os.unlink(self)
 490 
 491 
 492     # --- Links
 493 
 494     if hasattr(os, 'link'):
 495         def link(self, newpath):
 496             """ Create a hard link at 'newpath', pointing to this file. """
 497             os.link(self, newpath)
 498 
 499     if hasattr(os, 'symlink'):
 500         def symlink(self, newlink):
 501             """ Create a symbolic link at 'newlink', pointing here. """
 502             os.symlink(self, newlink)
 503 
 504     if hasattr(os, 'readlink'):
 505         def readlink(self):
 506             """ Return the path to which this symbolic link points.
 507 
 508             The result may be an absolute or a relative path.
 509             """
 510             return self.__class__(os.readlink(self))
 511 
 512         def readlinkabs(self):
 513             """ Return the path to which this symbolic link points.
 514 
 515             The result is always an absolute path.
 516             """
 517             p = self.readlink()
 518             if p.isabs():
 519                 return p
 520             else:
 521                 return self.__class__(self.parent, p).abspath()
 522 
 523 
 524     # --- High-level functions from shutil
 525 
 526     copyfile = shutil.copyfile
 527     copymode = shutil.copymode
 528     copystat = shutil.copystat
 529     copy = shutil.copy
 530     copy2 = shutil.copy2
 531     copytree = shutil.copytree
 532     if hasattr(shutil, 'move'):
 533         move = shutil.move
 534     rmtree = shutil.rmtree
 535 
 536 
 537     # --- Special stuff from os
 538 
 539     if hasattr(os, 'chroot'):
 540         def chroot(self):
 541             os.chroot(self)

EditText (last edited 2006-02-04 17:58:55 by ppp-68-122-72-154)