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

PathModule (last edited 2008-11-15 14:00:10 by localhost)

Unable to edit the page? See the FrontPage for instructions.