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
22
23
24
25
26
27
28
29
30
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
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
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
62 try:
63 True, False
64 except NameError:
65 True, False = 1, 0
66
67
68 try:
69 basestring
70 except NameError:
71 basestring = (str, unicode)
72
73
74 _textmode = 'r'
75 if hasattr(file, 'newlines'):
76 _textmode = 'U'
77
78
81
83 """ Represents a filesystem path.
84
85 For documentation on individual methods, consult their
86 counterparts in os.path.
87 """
88
89
90
92 return 'path(%s)' % _base.__repr__(self)
93
94
96 try:
97 resultStr = _base.__add__(self, more)
98 except TypeError:
99 resultStr = NotImplemented
100 if resultStr is NotImplemented:
101 return resultStr
102 return self.__class__(resultStr)
103
105 if isinstance(other, basestring):
106 return self.__class__(other.__add__(self))
107 else:
108 return NotImplemented
109
110
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
120 __truediv__ = __div__
121
123 """ Return the current working directory as a path object. """
124 return cls(_getcwd())
125 getcwd = classmethod(getcwd)
126
127
128
129
130 isabs = os.path.isabs
138 basename = os.path.basename
139
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
152
156
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
194 """ p.splitpath() -> Return (p.parent, p.name). """
195 parent, child = os.path.split(self)
196 return self.__class__(parent), child
197
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
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'):
231 unc, rest = os.path.splitunc(self)
232 return self.__class__(unc), rest
233
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
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
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
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
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
291 dest_list = dest.splitall()
292
293 if orig_list[0] != os.path.normcase(dest_list[0]):
294
295 return dest
296
297
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
305
306
307 segments = [os.pardir] * (len(orig_list) - i)
308
309 segments += dest_list[i:]
310 if len(segments) == 0:
311
312 relpath = os.curdir
313 else:
314 relpath = os.path.join(*segments)
315 return self.__class__(relpath)
316
317
318
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
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
518
519 - def open(self, mode='r'):
520 """ Open this file. Return a file object. """
521 return file(self, mode)
522
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
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
564 f = self.open(_textmode)
565 try:
566 return f.read()
567 finally:
568 f.close()
569 else:
570
571 f = codecs.open(self, 'r', encoding, errors)
572
573
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
651
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
663
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
742
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
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
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'):
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
821 """ Perform a stat() system call on this path. """
822 return os.stat(self)
823
825 """ Like path.stat(), but do not follow symbolic links. """
826 return os.lstat(self)
827
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'):
856 """ Perform a statvfs() system call on this path. """
857 return os.statvfs(self)
858
859 if hasattr(os, 'pathconf'):
862
863
864
865
867 """ Set the access and modified times of this file. """
868 os.utime(self, times)
869
872
873 if hasattr(os, 'chown'):
874 - def chown(self, uid, gid):
875 os.chown(self, uid, gid)
876
879
882
883
884
885
886 - def mkdir(self, mode=0777):
888
891
894
897
898
899
900
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
911
914
915
916
917
918 if hasattr(os, 'link'):
919 - def link(self, newpath):
920 """ Create a hard link at 'newpath', pointing to this file. """
921 os.link(self, newpath)
922
923 if hasattr(os, 'symlink'):
925 """ Create a symbolic link at 'newlink', pointing here. """
926 os.symlink(self, newlink)
927
928 if hasattr(os, 'readlink'):
930 """ Return the path to which this symbolic link points.
931
932 The result may be an absolute or a relative path.
933 """
934 return self.__class__(os.readlink(self))
935
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
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
962
963 if hasattr(os, 'chroot'):
966
967 if hasattr(os, 'startfile'):
970