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