Package commons :: Module path
[hide private]
[frames] | no frames]

Source Code for Module commons.path

  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.6 or later.
 
 11  
 
 12  
 
 13  URL:     http://www.jorendorff.com/articles/python/path
 
 14  
 
 15  @author: Jason Orendorff <jason.orendorff\x40gmail\x2ecom> (and others - see the url!)
 
 16  @author: Yang Zhang <yaaang\x40gmail\x2ecom>
 
 17  @date:   2009
 
 18  """ 
 19  
 
 20  
 
 21  # TODO
 
 22  #   - Tree-walking functions don't avoid symlink loops.  Matt Harrison
 
 23  #     sent me a patch for this.
 
 24  #   - Bug in write_text().  It doesn't support Universal newline mode.
 
 25  #   - Better error message in listdir() when self isn't a
 
 26  #     directory. (On Windows, the error message really sucks.)
 
 27  #   - Make sure everything has a good docstring.
 
 28  #   - Add methods for regex find and replace.
 
 29  #   - guess_content_type() method?
 
 30  #   - Perhaps support arguments to touch().
 
 31  
 
 32  from __future__ import generators 
 33  
 
 34  import sys, warnings, os, fnmatch, glob, shutil, codecs, hashlib 
 35  
 
 36  __version__ = '2.6' 
 37  __all__ = ['path'] 
 38  
 
 39  # Platform-specific support for path.owner
 
 40  if os.name == 'nt': 
 41      try: 
 42          import win32security 
 43      except ImportError: 
 44          win32security = None 
 45  else: 
 46      try: 
 47          import pwd 
 48      except ImportError: 
 49          pwd = None 
 50  
 
 51  # Pre-2.3 support.  Are unicode filenames supported?
 
 52  _base = str 
 53  _getcwd = os.getcwd 
 54  try: 
 55      if os.path.supports_unicode_filenames: 
 56          _base = unicode 
 57          _getcwd = os.getcwdu 
 58  except AttributeError: 
 59      pass 
 60  
 
 61  # Pre-2.3 workaround for booleans
 
 62  try: 
 63      True, False 
 64  except NameError: 
 65      True, False = 1, 0 
 66  
 
 67  # Pre-2.3 workaround for basestring.
 
 68  try: 
 69      basestring 
 70  except NameError: 
 71      basestring = (str, unicode) 
 72  
 
 73  # Universal newline support
 
 74  _textmode = 'r' 
 75  if hasattr(file, 'newlines'): 
 76      _textmode = 'U' 
 77  
 
 78  
 
79 -class TreeWalkWarning(Warning):
80 pass
81
82 -class path(_base):
83 """ Represents a filesystem path. 84 85 For documentation on individual methods, consult their 86 counterparts in os.path. 87 """ 88 89 # --- Special Python methods. 90
91 - def __repr__(self):
92 return 'path(%s)' % _base.__repr__(self)
93 94 # Adding a path and a string yields a path.
95 - def __add__(self, more):
96 try: 97 resultStr = _base.__add__(self, more) 98 except TypeError: #Python bug 99 resultStr = NotImplemented 100 if resultStr is NotImplemented: 101 return resultStr 102 return self.__class__(resultStr)
103
104 - def __radd__(self, other):
105 if isinstance(other, basestring): 106 return self.__class__(other.__add__(self)) 107 else: 108 return NotImplemented
109 110 # The / operator joins paths.
111 - def __div__(self, rel):
112 """ fp.__div__(rel) == fp / rel == fp.joinpath(rel) 113 114 Join two path components, adding a separator character if 115 needed. 116 """ 117 return self.__class__(os.path.join(self, rel))
118 119 # Make the / operator work even when true division is enabled. 120 __truediv__ = __div__ 121
122 - def getcwd(cls):
123 """ Return the current working directory as a path object. """ 124 return cls(_getcwd())
125 getcwd = classmethod(getcwd) 126 127 128 # --- Operations on path strings. 129 130 isabs = os.path.isabs
131 - def abspath(self): return self.__class__(os.path.abspath(self))
132 - def normcase(self): return self.__class__(os.path.normcase(self))
133 - def normpath(self): return self.__class__(os.path.normpath(self))
134 - def realpath(self): return self.__class__(os.path.realpath(self))
135 - def expanduser(self): return self.__class__(os.path.expanduser(self))
136 - def expandvars(self): return self.__class__(os.path.expandvars(self))
137 - def dirname(self): return self.__class__(os.path.dirname(self))
138 basename = os.path.basename 139
140 - def expand(self):
141 """ Clean up a filename by calling expandvars(), 142 expanduser(), and normpath() on it. 143 144 This is commonly everything needed to clean up a filename 145 read from a configuration file, for example. 146 """ 147 return self.expandvars().expanduser().normpath()
148
149 - def _get_namebase(self):
150 base, ext = os.path.splitext(self.name) 151 return base
152
153 - def _get_ext(self):
154 f, ext = os.path.splitext(_base(self)) 155 return ext
156
157 - def _get_drive(self):
158 drive, r = os.path.splitdrive(self) 159 return self.__class__(drive)
160 161 parent = property( 162 dirname, None, None, 163 """ This path's parent directory, as a new path object. 164 165 For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib') 166 """) 167 168 name = property( 169 basename, None, None, 170 """ The name of this file or directory without the full path. 171 172 For example, path('/usr/local/lib/libpython.so').name == 'libpython.so' 173 """) 174 175 namebase = property( 176 _get_namebase, None, None, 177 """ The same as path.name, but with one file extension stripped off. 178 179 For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz', 180 but path('/home/guido/python.tar.gz').namebase == 'python.tar' 181 """) 182 183 ext = property( 184 _get_ext, None, None, 185 """ The file extension, for example '.py'. """) 186 187 drive = property( 188 _get_drive, None, None, 189 """ The drive specifier, for example 'C:'. 190 This is always empty on systems that don't use drive specifiers. 191 """) 192
193 - def splitpath(self):
194 """ p.splitpath() -> Return (p.parent, p.name). """ 195 parent, child = os.path.split(self) 196 return self.__class__(parent), child
197
198 - def splitdrive(self):
199 """ p.splitdrive() -> Return (p.drive, <the rest of p>). 200 201 Split the drive specifier from this path. If there is 202 no drive specifier, p.drive is empty, so the return value 203 is simply (path(''), p). This is always the case on Unix. 204 """ 205 drive, rel = os.path.splitdrive(self) 206 return self.__class__(drive), rel
207
208 - def splitext(self):
209 """ p.splitext() -> Return (p.stripext(), p.ext). 210 211 Split the filename extension from this path and return 212 the two parts. Either part may be empty. 213 214 The extension is everything from '.' to the end of the 215 last path segment. This has the property that if 216 (a, b) == p.splitext(), then a + b == p. 217 """ 218 filename, ext = os.path.splitext(self) 219 return self.__class__(filename), ext
220
221 - def stripext(self):
222 """ p.stripext() -> Remove one file extension from the path. 223 224 For example, path('/home/guido/python.tar.gz').stripext() 225 returns path('/home/guido/python.tar'). 226 """ 227 return self.splitext()[0]
228 229 if hasattr(os.path, 'splitunc'):
230 - def splitunc(self):
231 unc, rest = os.path.splitunc(self) 232 return self.__class__(unc), rest
233
234 - def _get_uncshare(self):
235 unc, r = os.path.splitunc(self) 236 return self.__class__(unc)
237 238 uncshare = property( 239 _get_uncshare, None, None, 240 """ The UNC mount point for this path. 241 This is empty for paths on local drives. """) 242
243 - def joinpath(self, *args):
244 """ Join two or more path components, adding a separator 245 character (os.sep) if needed. Returns a new path 246 object. 247 """ 248 return self.__class__(os.path.join(self, *args))
249
250 - def splitall(self):
251 r""" Return a list of the path components in this path. 252 253 The first item in the list will be a path. Its value will be 254 either os.curdir, os.pardir, empty, or the root directory of 255 this path (for example, '/' or 'C:\\'). The other items in 256 the list will be strings. 257 258 path.path.joinpath(*result) will yield the original path. 259 """ 260 parts = [] 261 loc = self 262 while loc != os.curdir and loc != os.pardir: 263 prev = loc 264 loc, child = prev.splitpath() 265 if loc == prev: 266 break 267 parts.append(child) 268 parts.append(loc) 269 parts.reverse() 270 return parts
271
272 - def relpath(self):
273 """ Return this path as a relative path, 274 based from the current working directory. 275 """ 276 cwd = self.__class__(os.getcwd()) 277 return cwd.relpathto(self)
278
279 - def relpathto(self, dest):
280 """ Return a relative path from self to dest. 281 282 If there is no relative path from self to dest, for example if 283 they reside on different drives in Windows, then this returns 284 dest.abspath(). 285 """ 286 origin = self.abspath() 287 dest = self.__class__(dest).abspath() 288 289 orig_list = origin.normcase().splitall() 290 # Don't normcase dest! We want to preserve the case. 291 dest_list = dest.splitall() 292 293 if orig_list[0] != os.path.normcase(dest_list[0]): 294 # Can't get here from there. 295 return dest 296 297 # Find the location where the two paths start to differ. 298 i = 0 299 for start_seg, dest_seg in zip(orig_list, dest_list): 300 if start_seg != os.path.normcase(dest_seg): 301 break 302 i += 1 303 304 # Now i is the point where the two paths diverge. 305 # Need a certain number of "os.pardir"s to work up 306 # from the origin to the point of divergence. 307 segments = [os.pardir] * (len(orig_list) - i) 308 # Need to add the diverging part of dest_list. 309 segments += dest_list[i:] 310 if len(segments) == 0: 311 # If they happen to be identical, use os.curdir. 312 relpath = os.curdir 313 else: 314 relpath = os.path.join(*segments) 315 return self.__class__(relpath)
316 317 # --- Listing, searching, walking, and matching 318
319 - def listdir(self, pattern=None):
320 """ D.listdir() -> List of items in this directory. 321 322 Use D.files() or D.dirs() instead if you want a listing 323 of just files or just subdirectories. 324 325 The elements of the list are path objects. 326 327 With the optional 'pattern' argument, this only lists 328 items whose names match the given pattern. 329 """ 330 names = os.listdir(self) 331 if pattern is not None: 332 names = fnmatch.filter(names, pattern) 333 return [self / child for child in names]
334
335 - def dirs(self, pattern=None):
336 """ D.dirs() -> List of this directory's subdirectories. 337 338 The elements of the list are path objects. 339 This does not walk recursively into subdirectories 340 (but see path.walkdirs). 341 342 With the optional 'pattern' argument, this only lists 343 directories whose names match the given pattern. For 344 example, d.dirs('build-*'). 345 """ 346 return [p for p in self.listdir(pattern) if p.isdir()]
347
348 - def files(self, pattern=None):
349 """ D.files() -> List of the files in this directory. 350 351 The elements of the list are path objects. 352 This does not walk into subdirectories (see path.walkfiles). 353 354 With the optional 'pattern' argument, this only lists files 355 whose names match the given pattern. For example, 356 d.files('*.pyc'). 357 """ 358 359 return [p for p in self.listdir(pattern) if p.isfile()]
360
361 - def walk(self, pattern=None, errors='strict'):
362 """ D.walk() -> iterator over files and subdirs, recursively. 363 364 The iterator yields path objects naming each child item of 365 this directory and its descendants. This requires that 366 D.isdir(). 367 368 This performs a depth-first traversal of the directory tree. 369 Each directory is returned just before all its children. 370 371 The errors= keyword argument controls behavior when an 372 error occurs. The default is 'strict', which causes an 373 exception. The other allowed values are 'warn', which 374 reports the error via warnings.warn(), and 'ignore'. 375 """ 376 if errors not in ('strict', 'warn', 'ignore'): 377 raise ValueError("invalid errors parameter") 378 379 try: 380 childList = self.listdir() 381 except Exception: 382 if errors == 'ignore': 383 return 384 elif errors == 'warn': 385 warnings.warn( 386 "Unable to list directory '%s': %s" 387 % (self, sys.exc_info()[1]), 388 TreeWalkWarning) 389 return 390 else: 391 raise 392 393 for child in childList: 394 if pattern is None or child.fnmatch(pattern): 395 yield child 396 try: 397 isdir = child.isdir() 398 except Exception: 399 if errors == 'ignore': 400 isdir = False 401 elif errors == 'warn': 402 warnings.warn( 403 "Unable to access '%s': %s" 404 % (child, sys.exc_info()[1]), 405 TreeWalkWarning) 406 isdir = False 407 else: 408 raise 409 410 if isdir: 411 for item in child.walk(pattern, errors): 412 yield item
413
414 - def walkdirs(self, pattern=None, errors='strict'):
415 """ D.walkdirs() -> iterator over subdirs, recursively. 416 417 With the optional 'pattern' argument, this yields only 418 directories whose names match the given pattern. For 419 example, mydir.walkdirs('*test') yields only directories 420 with names ending in 'test'. 421 422 The errors= keyword argument controls behavior when an 423 error occurs. The default is 'strict', which causes an 424 exception. The other allowed values are 'warn', which 425 reports the error via warnings.warn(), and 'ignore'. 426 """ 427 if errors not in ('strict', 'warn', 'ignore'): 428 raise ValueError("invalid errors parameter") 429 430 try: 431 dirs = self.dirs() 432 except Exception: 433 if errors == 'ignore': 434 return 435 elif errors == 'warn': 436 warnings.warn( 437 "Unable to list directory '%s': %s" 438 % (self, sys.exc_info()[1]), 439 TreeWalkWarning) 440 return 441 else: 442 raise 443 444 for child in dirs: 445 if pattern is None or child.fnmatch(pattern): 446 yield child 447 for subsubdir in child.walkdirs(pattern, errors): 448 yield subsubdir
449
450 - def walkfiles(self, pattern=None, errors='strict'):
451 """ D.walkfiles() -> iterator over files in D, recursively. 452 453 The optional argument, pattern, limits the results to files 454 with names that match the pattern. For example, 455 mydir.walkfiles('*.tmp') yields only files with the .tmp 456 extension. 457 """ 458 if errors not in ('strict', 'warn', 'ignore'): 459 raise ValueError("invalid errors parameter") 460 461 try: 462 childList = self.listdir() 463 except Exception: 464 if errors == 'ignore': 465 return 466 elif errors == 'warn': 467 warnings.warn( 468 "Unable to list directory '%s': %s" 469 % (self, sys.exc_info()[1]), 470 TreeWalkWarning) 471 return 472 else: 473 raise 474 475 for child in childList: 476 try: 477 isfile = child.isfile() 478 isdir = not isfile and child.isdir() 479 except: 480 if errors == 'ignore': 481 continue 482 elif errors == 'warn': 483 warnings.warn( 484 "Unable to access '%s': %s" 485 % (self, sys.exc_info()[1]), 486 TreeWalkWarning) 487 continue 488 else: 489 raise 490 491 if isfile: 492 if pattern is None or child.fnmatch(pattern): 493 yield child 494 elif isdir: 495 for f in child.walkfiles(pattern, errors): 496 yield f
497
498 - def fnmatch(self, pattern):
499 """ Return True if self.name matches the given pattern. 500 501 @param pattern: A filename pattern with wildcards, for example '*.py'. 502 """ 503 return fnmatch.fnmatch(self.name, pattern)
504
505 - def glob(self, pattern):
506 """ Return a list of path objects that match the pattern. 507 508 @param pattern: A path relative to this directory, with wildcards. 509 510 For example, path('/users').glob('*/bin/*') returns a list 511 of all the files users have in their bin directories. 512 """ 513 cls = self.__class__ 514 return [cls(s) for s in glob.glob(_base(self / pattern))]
515 516 517 # --- Reading or writing an entire file at once. 518
519 - def open(self, mode='r'):
520 """ Open this file. Return a file object. """ 521 return file(self, mode)
522
523 - def bytes(self):
524 """ Open this file, read all bytes, return them as a string. """ 525 f = self.open('rb') 526 try: 527 return f.read() 528 finally: 529 f.close()
530
531 - def write_bytes(self, bytes, append=False):
532 """ Open this file and write the given bytes to it. 533 534 Default behavior is to overwrite any existing file. 535 Call p.write_bytes(bytes, append=True) to append instead. 536 """ 537 if append: 538 mode = 'ab' 539 else: 540 mode = 'wb' 541 f = self.open(mode) 542 try: 543 f.write(bytes) 544 finally: 545 f.close()
546
547 - def text(self, encoding=None, errors='strict'):
548 r""" Open this file, read it in, return the content as a string. 549 550 This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r' 551 are automatically translated to '\n'. 552 553 Optional arguments: 554 555 @param encoding: The Unicode encoding (or character set) of 556 the file. If present, the content of the file is 557 decoded and returned as a unicode object; otherwise 558 it is returned as an 8-bit str. 559 @param errors: How to handle Unicode errors; see help(str.decode) 560 for the options. Default is 'strict'. 561 """ 562 if encoding is None: 563 # 8-bit 564 f = self.open(_textmode) 565 try: 566 return f.read() 567 finally: 568 f.close() 569 else: 570 # Unicode 571 f = codecs.open(self, 'r', encoding, errors) 572 # (Note - Can't use 'U' mode here, since codecs.open 573 # doesn't support 'U' mode, even in Python 2.3.) 574 try: 575 t = f.read() 576 finally: 577 f.close() 578 return (t.replace(u'\r\n', u'\n') 579 .replace(u'\r\x85', u'\n') 580 .replace(u'\r', u'\n') 581 .replace(u'\x85', u'\n') 582 .replace(u'\u2028', u'\n'))
583
584 - def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False):
585 r""" Write the given text to this file. 586 587 The default behavior is to overwrite any existing file; 588 to append instead, use the 'append=True' keyword argument. 589 590 There are two differences between path.write_text() and 591 path.write_bytes(): newline handling and Unicode handling. 592 See below. 593 594 Parameters: 595 596 - text - str/unicode - The text to be written. 597 598 - encoding - str - The Unicode encoding that will be used. 599 This is ignored if 'text' isn't a Unicode string. 600 601 - errors - str - How to handle Unicode encoding errors. 602 Default is 'strict'. See help(unicode.encode) for the 603 options. This is ignored if 'text' isn't a Unicode 604 string. 605 606 - linesep - keyword argument - str/unicode - The sequence of 607 characters to be used to mark end-of-line. The default is 608 os.linesep. You can also specify None; this means to 609 leave all newlines as they are in 'text'. 610 611 - append - keyword argument - bool - Specifies what to do if 612 the file already exists (True: append to the end of it; 613 False: overwrite it.) The default is False. 614 615 616 --- Newline handling. 617 618 write_text() converts all standard end-of-line sequences 619 ('\n', '\r', and '\r\n') to your platform's default end-of-line 620 sequence (see os.linesep; on Windows, for example, the 621 end-of-line marker is '\r\n'). 622 623 If you don't like your platform's default, you can override it 624 using the 'linesep=' keyword argument. If you specifically want 625 write_text() to preserve the newlines as-is, use 'linesep=None'. 626 627 This applies to Unicode text the same as to 8-bit text, except 628 there are three additional standard Unicode end-of-line sequences: 629 u'\x85', u'\r\x85', and u'\u2028'. 630 631 (This is slightly different from when you open a file for 632 writing with fopen(filename, "w") in C or file(filename, 'w') 633 in Python.) 634 635 636 --- Unicode 637 638 If 'text' isn't Unicode, then apart from newline handling, the 639 bytes are written verbatim to the file. The 'encoding' and 640 'errors' arguments are not used and must be omitted. 641 642 If 'text' is Unicode, it is first converted to bytes using the 643 specified 'encoding' (or the default encoding if 'encoding' 644 isn't specified). The 'errors' argument applies only to this 645 conversion. 646 647 """ 648 if isinstance(text, unicode): 649 if linesep is not None: 650 # Convert all standard end-of-line sequences to 651 # ordinary newline characters. 652 text = (text.replace(u'\r\n', u'\n') 653 .replace(u'\r\x85', u'\n') 654 .replace(u'\r', u'\n') 655 .replace(u'\x85', u'\n') 656 .replace(u'\u2028', u'\n')) 657 text = text.replace(u'\n', linesep) 658 if encoding is None: 659 encoding = sys.getdefaultencoding() 660 bytes = text.encode(encoding, errors) 661 else: 662 # It is an error to specify an encoding if 'text' is 663 # an 8-bit string. 664 assert encoding is None 665 666 if linesep is not None: 667 text = (text.replace('\r\n', '\n') 668 .replace('\r', '\n')) 669 bytes = text.replace('\n', linesep) 670 671 self.write_bytes(bytes, append)
672
673 - def lines(self, encoding=None, errors='strict', retain=True):
674 r""" Open this file, read all lines, return them in a list. 675 676 This uses 'U' mode in Python 2.3 and later. 677 678 @param encoding: The Unicode encoding (or character set) of 679 the file. The default is None, meaning the content 680 of the file is read as 8-bit characters and returned 681 as a list of (non-Unicode) str objects. 682 @param errors: How to handle Unicode errors; see help(str.decode) 683 for the options. Default is 'strict' 684 @param retain: If true, retain newline characters; but all newline 685 character combinations ('\r', '\n', '\r\n') are 686 translated to '\n'. If false, newline characters are 687 stripped off. Default is True. 688 """ 689 if encoding is None and retain: 690 f = self.open(_textmode) 691 try: 692 return f.readlines() 693 finally: 694 f.close() 695 else: 696 return self.text(encoding, errors).splitlines(retain)
697
698 - def write_lines(self, lines, encoding=None, errors='strict', 699 linesep=os.linesep, append=False):
700 r""" Write the given lines of text to this file. 701 702 By default this overwrites any existing file at this path. 703 704 This puts a platform-specific newline sequence on every line. 705 See 'linesep' below. 706 707 @param lines: A list of strings. 708 709 @param encoding: A Unicode encoding to use. This applies only if 710 'lines' contains any Unicode strings. 711 712 @param errors: How to handle errors in Unicode encoding. This 713 also applies only to Unicode strings. 714 715 @param linesep: The desired line-ending. This line-ending is 716 applied to every line. If a line already has any 717 standard line ending ('\r', '\n', '\r\n', u'\x85', 718 u'\r\x85', u'\u2028'), that will be stripped off and 719 this will be used instead. The default is os.linesep, 720 which is platform-dependent ('\r\n' on Windows, '\n' on 721 Unix, etc.) Specify None to write the lines as-is, 722 like file.writelines(). 723 724 @param append: Append lines to the 725 file. The default is to overwrite the file. Warning: 726 When you use this with Unicode data, if the encoding of the 727 existing data in the file is different from the encoding 728 you specify with the encoding= parameter, the result is 729 mixed-encoding data, which can really confuse someone trying 730 to read the file later. 731 """ 732 if append: 733 mode = 'ab' 734 else: 735 mode = 'wb' 736 f = self.open(mode) 737 try: 738 for line in lines: 739 isUnicode = isinstance(line, unicode) 740 if linesep is not None: 741 # Strip off any existing line-end and add the 742 # specified linesep string. 743 if isUnicode: 744 if line[-2:] in (u'\r\n', u'\x0d\x85'): 745 line = line[:-2] 746 elif line[-1:] in (u'\r', u'\n', 747 u'\x85', u'\u2028'): 748 line = line[:-1] 749 else: 750 if line[-2:] == '\r\n': 751 line = line[:-2] 752 elif line[-1:] in ('\r', '\n'): 753 line = line[:-1] 754 line += linesep 755 if isUnicode: 756 if encoding is None: 757 encoding = sys.getdefaultencoding() 758 line = line.encode(encoding, errors) 759 f.write(line) 760 finally: 761 f.close()
762
763 - def read_md5(self):
764 """ Calculate the md5 hash for this file. 765 766 This reads through the entire file. 767 """ 768 f = self.open('rb') 769 try: 770 m = hashlib.md5() 771 while True: 772 d = f.read(8192) 773 if not d: 774 break 775 m.update(d) 776 finally: 777 f.close() 778 return m.digest()
779 780 # --- Methods for querying the filesystem. 781 782 exists = os.path.exists 783 isdir = os.path.isdir 784 isfile = os.path.isfile 785 islink = os.path.islink 786 ismount = os.path.ismount 787 788 if hasattr(os.path, 'samefile'): 789 samefile = os.path.samefile 790 791 getatime = os.path.getatime 792 atime = property( 793 getatime, None, None, 794 """ Last access time of the file. """) 795 796 getmtime = os.path.getmtime 797 mtime = property( 798 getmtime, None, None, 799 """ Last-modified time of the file. """) 800 801 if hasattr(os.path, 'getctime'): 802 getctime = os.path.getctime 803 ctime = property( 804 getctime, None, None, 805 """ Creation time of the file. """) 806 807 getsize = os.path.getsize 808 size = property( 809 getsize, None, None, 810 """ Size of the file, in bytes. """) 811 812 if hasattr(os, 'access'):
813 - def access(self, mode):
814 """ Return true if current user has access to this path. 815 816 mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK 817 """ 818 return os.access(self, mode)
819
820 - def stat(self):
821 """ Perform a stat() system call on this path. """ 822 return os.stat(self)
823
824 - def lstat(self):
825 """ Like path.stat(), but do not follow symbolic links. """ 826 return os.lstat(self)
827
828 - def get_owner(self):
829 r""" Return the name of the owner of this file or directory. 830 831 This follows symbolic links. 832 833 On Windows, this returns a name of the form ur'DOMAIN\User Name'. 834 On Windows, a group can own a file or directory. 835 """ 836 if os.name == 'nt': 837 if win32security is None: 838 raise Exception("path.owner requires win32all to be installed") 839 desc = win32security.GetFileSecurity( 840 self, win32security.OWNER_SECURITY_INFORMATION) 841 sid = desc.GetSecurityDescriptorOwner() 842 account, domain, typecode = win32security.LookupAccountSid(None, sid) 843 return domain + u'\\' + account 844 else: 845 if pwd is None: 846 raise NotImplementedError("path.owner is not implemented on this platform.") 847 st = self.stat() 848 return pwd.getpwuid(st.st_uid).pw_name
849 850 owner = property( 851 get_owner, None, None, 852 """ Name of the owner of this file or directory. """) 853 854 if hasattr(os, 'statvfs'):
855 - def statvfs(self):
856 """ Perform a statvfs() system call on this path. """ 857 return os.statvfs(self)
858 859 if hasattr(os, 'pathconf'):
860 - def pathconf(self, name):
861 return os.pathconf(self, name)
862 863 864 # --- Modifying operations on files and directories 865
866 - def utime(self, times):
867 """ Set the access and modified times of this file. """ 868 os.utime(self, times)
869
870 - def chmod(self, mode):
871 os.chmod(self, mode)
872 873 if hasattr(os, 'chown'):
874 - def chown(self, uid, gid):
875 os.chown(self, uid, gid)
876
877 - def rename(self, new):
878 os.rename(self, new)
879
880 - def renames(self, new):
881 os.renames(self, new)
882 883 884 # --- Create/delete operations on directories 885
886 - def mkdir(self, mode=0777):
887 os.mkdir(self, mode)
888
889 - def makedirs(self, mode=0777):
890 os.makedirs(self, mode)
891
892 - def rmdir(self):
893 os.rmdir(self)
894
895 - def removedirs(self):
896 os.removedirs(self)
897 898 899 # --- Modifying operations on files 900
901 - def touch(self):
902 """ Set the access/modified times of this file to the current time. 903 Create the file if it does not exist. 904 """ 905 fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666) 906 os.close(fd) 907 os.utime(self, None)
908
909 - def remove(self):
910 os.remove(self)
911 914 915 916 # --- Links 917 918 if hasattr(os, 'link'): 922 923 if hasattr(os, 'symlink'): 927 928 if hasattr(os, 'readlink'): 935
936 - def readlinkabs(self):
937 """ Return the path to which this symbolic link points. 938 939 The result is always an absolute path. 940 """ 941 p = self.readlink() 942 if p.isabs(): 943 return p 944 else: 945 return (self.parent / p).abspath()
946 947 948 # --- High-level functions from shutil 949 950 copyfile = shutil.copyfile 951 copymode = shutil.copymode 952 copystat = shutil.copystat 953 copy = shutil.copy 954 copy2 = shutil.copy2 955 copytree = shutil.copytree 956 if hasattr(shutil, 'move'): 957 move = shutil.move 958 rmtree = shutil.rmtree 959 960 961 # --- Special stuff from os 962 963 if hasattr(os, 'chroot'):
964 - def chroot(self):
965 os.chroot(self)
966 967 if hasattr(os, 'startfile'):
968 - def startfile(self):
969 os.startfile(self)
970