##// END OF EJS Templates
upgraded to path.py v2.1
vivainio -
Show More
@@ -11,23 +11,18 b' This module requires Python 2.2 or later.'
11 11
12 12
13 13 URL: http://www.jorendorff.com/articles/python/path
14 Author: Jason Orendorff <jason@jorendorff.com> (and others - see the url!)
14 Author: Jason Orendorff <jason.orendorff\x40gmail\x2ecom> (and others - see the url!)
15 15 Date: 7 Mar 2004
16 16 """
17 17
18 # Original license statement:
19 #License: You may use path.py for whatever you wish, at your own risk. (For
20 #example, you may modify, relicense, and redistribute it.) It is provided
21 #without any guarantee or warranty of any kind, not even for merchantability or
22 #fitness for any purpose.
23
24 # IPython license note:
25 # For the sake of convenience, IPython includes this module
26 # in its directory structure in unmodified form, apart from
27 # these license statements. The same license still applies.
28
29 18
30 19 # TODO
20 # - Tree-walking functions don't avoid symlink loops. Matt Harrison sent me a patch for this.
21 # - Tree-walking functions can't ignore errors. Matt Harrison asked for this.
22 #
23 # - Two people asked for path.chdir(). This just seems wrong to me,
24 # I dunno. chdir() is moderately evil anyway.
25 #
31 26 # - Bug in write_text(). It doesn't support Universal newline mode.
32 27 # - Better error message in listdir() when self isn't a
33 28 # directory. (On Windows, the error message really sucks.)
@@ -36,25 +31,42 b' Date: 7 Mar 2004'
36 31 # - guess_content_type() method?
37 32 # - Perhaps support arguments to touch().
38 33 # - Could add split() and join() methods that generate warnings.
39 # - Note: __add__() technically has a bug, I think, where
40 # it doesn't play nice with other types that implement
41 # __radd__(). Test this.
42 34
43 35 from __future__ import generators
44 36
45 import sys, os, fnmatch, glob, shutil, codecs
37 import sys, warnings, os, fnmatch, glob, shutil, codecs, md5
46 38
47 __version__ = '2.0.4'
39 __version__ = '2.1'
48 40 __all__ = ['path']
49 41
42 # Platform-specific support for path.owner
43 if os.name == 'nt':
44 try:
45 import win32security
46 except ImportError:
47 win32security = None
48 else:
49 try:
50 import pwd
51 except ImportError:
52 pwd = None
53
50 54 # Pre-2.3 support. Are unicode filenames supported?
51 55 _base = str
56 _getcwd = os.getcwd
52 57 try:
53 58 if os.path.supports_unicode_filenames:
54 59 _base = unicode
60 _getcwd = os.getcwdu
55 61 except AttributeError:
56 62 pass
57 63
64 # Pre-2.3 workaround for booleans
65 try:
66 True, False
67 except NameError:
68 True, False = 1, 0
69
58 70 # Pre-2.3 workaround for basestring.
59 71 try:
60 72 basestring
@@ -67,6 +79,9 b" if hasattr(file, 'newlines'):"
67 79 _textmode = 'U'
68 80
69 81
82 class TreeWalkWarning(Warning):
83 pass
84
70 85 class path(_base):
71 86 """ Represents a filesystem path.
72 87
@@ -81,10 +96,19 b' class path(_base):'
81 96
82 97 # Adding a path and a string yields a path.
83 98 def __add__(self, more):
84 return path(_base(self) + more)
99 try:
100 resultStr = _base.__add__(self, more)
101 except TypeError: #Python bug
102 resultStr = NotImplemented
103 if resultStr is NotImplemented:
104 return resultStr
105 return self.__class__(resultStr)
85 106
86 107 def __radd__(self, other):
87 return path(other + _base(self))
108 if isinstance(other, basestring):
109 return self.__class__(other.__add__(self))
110 else:
111 return NotImplemented
88 112
89 113 # The / operator joins paths.
90 114 def __div__(self, rel):
@@ -93,26 +117,27 b' class path(_base):'
93 117 Join two path components, adding a separator character if
94 118 needed.
95 119 """
96 return path(os.path.join(self, rel))
120 return self.__class__(os.path.join(self, rel))
97 121
98 122 # Make the / operator work even when true division is enabled.
99 123 __truediv__ = __div__
100 124
101 def getcwd():
125 def getcwd(cls):
102 126 """ Return the current working directory as a path object. """
103 return path(os.getcwd())
104 getcwd = staticmethod(getcwd)
127 return cls(_getcwd())
128 getcwd = classmethod(getcwd)
105 129
106 130
107 131 # --- Operations on path strings.
108 132
109 def abspath(self): return path(os.path.abspath(self))
110 def normcase(self): return path(os.path.normcase(self))
111 def normpath(self): return path(os.path.normpath(self))
112 def realpath(self): return path(os.path.realpath(self))
113 def expanduser(self): return path(os.path.expanduser(self))
114 def expandvars(self): return path(os.path.expandvars(self))
115 def dirname(self): return path(os.path.dirname(self))
133 isabs = os.path.isabs
134 def abspath(self): return self.__class__(os.path.abspath(self))
135 def normcase(self): return self.__class__(os.path.normcase(self))
136 def normpath(self): return self.__class__(os.path.normpath(self))
137 def realpath(self): return self.__class__(os.path.realpath(self))
138 def expanduser(self): return self.__class__(os.path.expanduser(self))
139 def expandvars(self): return self.__class__(os.path.expandvars(self))
140 def dirname(self): return self.__class__(os.path.dirname(self))
116 141 basename = os.path.basename
117 142
118 143 def expand(self):
@@ -134,7 +159,7 b' class path(_base):'
134 159
135 160 def _get_drive(self):
136 161 drive, r = os.path.splitdrive(self)
137 return path(drive)
162 return self.__class__(drive)
138 163
139 164 parent = property(
140 165 dirname, None, None,
@@ -171,7 +196,7 b' class path(_base):'
171 196 def splitpath(self):
172 197 """ p.splitpath() -> Return (p.parent, p.name). """
173 198 parent, child = os.path.split(self)
174 return path(parent), child
199 return self.__class__(parent), child
175 200
176 201 def splitdrive(self):
177 202 """ p.splitdrive() -> Return (p.drive, <the rest of p>).
@@ -181,7 +206,7 b' class path(_base):'
181 206 is simply (path(''), p). This is always the case on Unix.
182 207 """
183 208 drive, rel = os.path.splitdrive(self)
184 return path(drive), rel
209 return self.__class__(drive), rel
185 210
186 211 def splitext(self):
187 212 """ p.splitext() -> Return (p.stripext(), p.ext).
@@ -194,7 +219,7 b' class path(_base):'
194 219 (a, b) == p.splitext(), then a + b == p.
195 220 """
196 221 filename, ext = os.path.splitext(self)
197 return path(filename), ext
222 return self.__class__(filename), ext
198 223
199 224 def stripext(self):
200 225 """ p.stripext() -> Remove one file extension from the path.
@@ -207,11 +232,11 b' class path(_base):'
207 232 if hasattr(os.path, 'splitunc'):
208 233 def splitunc(self):
209 234 unc, rest = os.path.splitunc(self)
210 return path(unc), rest
235 return self.__class__(unc), rest
211 236
212 237 def _get_uncshare(self):
213 238 unc, r = os.path.splitunc(self)
214 return path(unc)
239 return self.__class__(unc)
215 240
216 241 uncshare = property(
217 242 _get_uncshare, None, None,
@@ -223,10 +248,10 b' class path(_base):'
223 248 character (os.sep) if needed. Returns a new path
224 249 object.
225 250 """
226 return path(os.path.join(self, *args))
251 return self.__class__(os.path.join(self, *args))
227 252
228 253 def splitall(self):
229 """ Return a list of the path components in this path.
254 r""" Return a list of the path components in this path.
230 255
231 256 The first item in the list will be a path. Its value will be
232 257 either os.curdir, os.pardir, empty, or the root directory of
@@ -251,7 +276,7 b' class path(_base):'
251 276 """ Return this path as a relative path,
252 277 based from the current working directory.
253 278 """
254 cwd = path(os.getcwd())
279 cwd = self.__class__(os.getcwd())
255 280 return cwd.relpathto(self)
256 281
257 282 def relpathto(self, dest):
@@ -262,7 +287,7 b' class path(_base):'
262 287 dest.abspath().
263 288 """
264 289 origin = self.abspath()
265 dest = path(dest).abspath()
290 dest = self.__class__(dest).abspath()
266 291
267 292 orig_list = origin.normcase().splitall()
268 293 # Don't normcase dest! We want to preserve the case.
@@ -287,10 +312,10 b' class path(_base):'
287 312 segments += dest_list[i:]
288 313 if len(segments) == 0:
289 314 # If they happen to be identical, use os.curdir.
290 return path(os.curdir)
315 relpath = os.curdir
291 316 else:
292 return path(os.path.join(*segments))
293
317 relpath = os.path.join(*segments)
318 return self.__class__(relpath)
294 319
295 320 # --- Listing, searching, walking, and matching
296 321
@@ -336,7 +361,7 b' class path(_base):'
336 361
337 362 return [p for p in self.listdir(pattern) if p.isfile()]
338 363
339 def walk(self, pattern=None):
364 def walk(self, pattern=None, errors='strict'):
340 365 """ D.walk() -> iterator over files and subdirs, recursively.
341 366
342 367 The iterator yields path objects naming each child item of
@@ -345,29 +370,85 b' class path(_base):'
345 370
346 371 This performs a depth-first traversal of the directory tree.
347 372 Each directory is returned just before all its children.
373
374 The errors= keyword argument controls behavior when an
375 error occurs. The default is 'strict', which causes an
376 exception. The other allowed values are 'warn', which
377 reports the error via warnings.warn(), and 'ignore'.
348 378 """
349 for child in self.listdir():
379 if errors not in ('strict', 'warn', 'ignore'):
380 raise ValueError("invalid errors parameter")
381
382 try:
383 childList = self.listdir()
384 except Exception:
385 if errors == 'ignore':
386 return
387 elif errors == 'warn':
388 warnings.warn(
389 "Unable to list directory '%s': %s"
390 % (self, sys.exc_info()[1]),
391 TreeWalkWarning)
392 else:
393 raise
394
395 for child in childList:
350 396 if pattern is None or child.fnmatch(pattern):
351 397 yield child
352 if child.isdir():
353 for item in child.walk(pattern):
398 try:
399 isdir = child.isdir()
400 except Exception:
401 if errors == 'ignore':
402 isdir = False
403 elif errors == 'warn':
404 warnings.warn(
405 "Unable to access '%s': %s"
406 % (child, sys.exc_info()[1]),
407 TreeWalkWarning)
408 isdir = False
409 else:
410 raise
411
412 if isdir:
413 for item in child.walk(pattern, errors):
354 414 yield item
355 415
356 def walkdirs(self, pattern=None):
416 def walkdirs(self, pattern=None, errors='strict'):
357 417 """ D.walkdirs() -> iterator over subdirs, recursively.
358 418
359 419 With the optional 'pattern' argument, this yields only
360 420 directories whose names match the given pattern. For
361 421 example, mydir.walkdirs('*test') yields only directories
362 422 with names ending in 'test'.
423
424 The errors= keyword argument controls behavior when an
425 error occurs. The default is 'strict', which causes an
426 exception. The other allowed values are 'warn', which
427 reports the error via warnings.warn(), and 'ignore'.
363 428 """
364 for child in self.dirs():
429 if errors not in ('strict', 'warn', 'ignore'):
430 raise ValueError("invalid errors parameter")
431
432 try:
433 dirs = self.dirs()
434 except Exception:
435 if errors == 'ignore':
436 return
437 elif errors == 'warn':
438 warnings.warn(
439 "Unable to list directory '%s': %s"
440 % (self, sys.exc_info()[1]),
441 TreeWalkWarning)
442 else:
443 raise
444
445 for child in dirs:
365 446 if pattern is None or child.fnmatch(pattern):
366 447 yield child
367 for subsubdir in child.walkdirs(pattern):
448 for subsubdir in child.walkdirs(pattern, errors):
368 449 yield subsubdir
369 450
370 def walkfiles(self, pattern=None):
451 def walkfiles(self, pattern=None, errors='strict'):
371 452 """ D.walkfiles() -> iterator over files in D, recursively.
372 453
373 454 The optional argument, pattern, limits the results to files
@@ -375,12 +456,42 b' class path(_base):'
375 456 mydir.walkfiles('*.tmp') yields only files with the .tmp
376 457 extension.
377 458 """
378 for child in self.listdir():
379 if child.isfile():
459 if errors not in ('strict', 'warn', 'ignore'):
460 raise ValueError("invalid errors parameter")
461
462 try:
463 childList = self.listdir()
464 except Exception:
465 if errors == 'ignore':
466 return
467 elif errors == 'warn':
468 warnings.warn(
469 "Unable to list directory '%s': %s"
470 % (self, sys.exc_info()[1]),
471 TreeWalkWarning)
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 return
482 elif errors == 'warn':
483 warnings.warn(
484 "Unable to access '%s': %s"
485 % (self, sys.exc_info()[1]),
486 TreeWalkWarning)
487 else:
488 raise
489
490 if isfile:
380 491 if pattern is None or child.fnmatch(pattern):
381 492 yield child
382 elif child.isdir():
383 for f in child.walkfiles(pattern):
493 elif isdir:
494 for f in child.walkfiles(pattern, errors):
384 495 yield f
385 496
386 497 def fnmatch(self, pattern):
@@ -399,7 +510,8 b' class path(_base):'
399 510 For example, path('/users').glob('*/bin/*') returns a list
400 511 of all the files users have in their bin directories.
401 512 """
402 return map(path, glob.glob(_base(self / pattern)))
513 cls = self.__class__
514 return [cls(s) for s in glob.glob(_base(self / pattern))]
403 515
404 516
405 517 # --- Reading or writing an entire file at once.
@@ -420,7 +532,7 b' class path(_base):'
420 532 """ Open this file and write the given bytes to it.
421 533
422 534 Default behavior is to overwrite any existing file.
423 Call this with write_bytes(bytes, append=True) to append instead.
535 Call p.write_bytes(bytes, append=True) to append instead.
424 536 """
425 537 if append:
426 538 mode = 'ab'
@@ -433,7 +545,7 b' class path(_base):'
433 545 f.close()
434 546
435 547 def text(self, encoding=None, errors='strict'):
436 """ Open this file, read it in, return the content as a string.
548 r""" Open this file, read it in, return the content as a string.
437 549
438 550 This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r'
439 551 are automatically translated to '\n'.
@@ -470,7 +582,7 b' class path(_base):'
470 582 .replace(u'\u2028', u'\n'))
471 583
472 584 def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False):
473 """ Write the given text to this file.
585 r""" Write the given text to this file.
474 586
475 587 The default behavior is to overwrite any existing file;
476 588 to append instead, use the 'append=True' keyword argument.
@@ -559,7 +671,7 b' class path(_base):'
559 671 self.write_bytes(bytes, append)
560 672
561 673 def lines(self, encoding=None, errors='strict', retain=True):
562 """ Open this file, read all lines, return them in a list.
674 r""" Open this file, read all lines, return them in a list.
563 675
564 676 Optional arguments:
565 677 encoding - The Unicode encoding (or character set) of
@@ -586,7 +698,7 b' class path(_base):'
586 698
587 699 def write_lines(self, lines, encoding=None, errors='strict',
588 700 linesep=os.linesep, append=False):
589 """ Write the given lines of text to this file.
701 r""" Write the given lines of text to this file.
590 702
591 703 By default this overwrites any existing file at this path.
592 704
@@ -649,11 +761,26 b' class path(_base):'
649 761 finally:
650 762 f.close()
651 763
764 def read_md5(self):
765 """ Calculate the md5 hash for this file.
766
767 This reads through the entire file.
768 """
769 f = self.open('rb')
770 try:
771 m = md5.new()
772 while True:
773 d = f.read(8192)
774 if not d:
775 break
776 m.update(d)
777 finally:
778 f.close()
779 return m.digest()
652 780
653 781 # --- Methods for querying the filesystem.
654 782
655 783 exists = os.path.exists
656 isabs = os.path.isabs
657 784 isdir = os.path.isdir
658 785 isfile = os.path.isfile
659 786 islink = os.path.islink
@@ -699,6 +826,32 b' class path(_base):'
699 826 """ Like path.stat(), but do not follow symbolic links. """
700 827 return os.lstat(self)
701 828
829 def get_owner(self):
830 r""" Return the name of the owner of this file or directory.
831
832 This follows symbolic links.
833
834 On Windows, this returns a name of the form ur'DOMAIN\User Name'.
835 On Windows, a group can own a file or directory.
836 """
837 if os.name == 'nt':
838 if win32security is None:
839 raise Exception("path.owner requires win32all to be installed")
840 desc = win32security.GetFileSecurity(
841 self, win32security.OWNER_SECURITY_INFORMATION)
842 sid = desc.GetSecurityDescriptorOwner()
843 account, domain, typecode = win32security.LookupAccountSid(None, sid)
844 return domain + u'\\' + account
845 else:
846 if pwd is None:
847 raise NotImplementedError("path.owner is not implemented on this platform.")
848 st = self.stat()
849 return pwd.getpwuid(st.st_uid).pw_name
850
851 owner = property(
852 get_owner, None, None,
853 """ Name of the owner of this file or directory. """)
854
702 855 if hasattr(os, 'statvfs'):
703 856 def statvfs(self):
704 857 """ Perform a statvfs() system call on this path. """
@@ -779,7 +932,7 b' class path(_base):'
779 932
780 933 The result may be an absolute or a relative path.
781 934 """
782 return path(os.readlink(self))
935 return self.__class__(os.readlink(self))
783 936
784 937 def readlinkabs(self):
785 938 """ Return the path to which this symbolic link points.
@@ -19,6 +19,10 b''
19 19 interesting (stored / manually defined) aliases last
20 20 where they catch the eye w/o scrolling.
21 21
22 * Magic.py (%rehashx), ext_rehashdir.py: files with
23 'py' extension are always considered executable, even
24 when not in PATHEXT environment variable.
25
22 26 2006-10-12 Ville Vainio <vivainio@gmail.com>
23 27
24 28 * jobctrl.py: Add new "jobctrl" extension for spawning background
General Comments 0
You need to be logged in to leave comments. Login now