1
2 """path.py - An object representing a path to a file or directory.
3
4 Example:
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.4 or later.
11
12 TODO
13 ----
14 - Tree-walking functions don't avoid symlink loops. Matt Harrison sent me a patch for this.
15 - Tree-walking functions can't ignore errors. Matt Harrison asked for this.
16
17 - Two people asked for path.chdir(). This just seems wrong to me,
18 I dunno. chdir() is moderately evil anyway.
19
20 - Bug in write_text(). It doesn't support Universal newline mode.
21 - Better error message in listdir() when self isn't a
22 directory. (On Windows, the error message really sucks.)
23 - Make sure everything has a good docstringc.
24 - Add methods for regex find and replace.
25 - guess_content_type() method?
26 - Could add split() and join() methods that generate warnings.
27 """
28 from __future__ import generators
29 __docformat__ = "restructuredtext"
30
31 __license__='Freeware'
32
33 import sys
34 import logging
35 import os
36 import fnmatch
37 import glob
38 import shutil
39 import codecs
40 import re
41 from interface import iDagItem
42 log = logging.getLogger("mrv.path")
43
44 __version__ = '3.0'
45 __all__ = ['Path', 'BasePath', 'make_path']
46
47
48 if os.name == 'nt':
49 try:
50 import win32security
51 except ImportError:
52 win32security = None
53 else:
54 try:
55 import pwd
56 except ImportError:
57 pwd = None
58
59
60 _base = str
61 _getcwd = os.getcwd
62 try:
63 if os.path.supports_unicode_filenames:
64 _base = unicode
65 _getcwd = os.getcwdu
66 except AttributeError:
67 pass
68
69
70 try:
71 True, False
72 except NameError:
73 True, False = 1, 0
74
75
76 try:
77 basestring
78 except NameError:
79 basestring = (str, unicode)
80
81
82 _textmode = 'r'
83 if hasattr(file, 'newlines'):
84 _textmode = 'U'
85
86
87
88 _varprog = re.compile(r'\$(\w+|\{[^}]*\})')
92
93
94 -class Path( _base, iDagItem ):
95 """ Represents a filesystem path.
96
97 For documentation on individual methods, consult their
98 counterparts in os.path.
99 """
100
101 sep = None
102 osep = None
103
104
105
107 return '%s(%s)' % ( self.__class__.__name__, _base.__repr__(self) )
108
109
111 try:
112 resultStr = _base.__add__(self, more)
113 except TypeError:
114 resultStr = NotImplemented
115 if resultStr is NotImplemented:
116 return resultStr
117 return self.__class__(resultStr)
118
124
125
127 """ fp.__div__(rel) == fp / rel == fp.joinpath(rel)
128
129 Join two path components, adding a separator character if
130 needed.
131 """
132 return self.__class__(os.path.join(self, rel))
133
134
135 __truediv__ = __div__
136
138 """Comparison method with expanded variables, just to assure
139 the comparison yields the results we would expect"""
140 return unicode(self._expandvars(self)) == unicode(self._expandvars(unicode(other)))
141
143 return not self.__eq__( other )
144
146 """Expanded hash method"""
147 return hash(unicode(self._expandvars(self)))
148
149
150
151 @classmethod
153 """Set this type to support the given separator as general path separator"""
154 if sep not in "/\\":
155 raise ValueError("Invalid path separator", sep)
156 cls.sep = sep
157 cls.osep = (sep == '/' and '\\') or "/"
158
159
160 global Path
161 if os.path.sep != cls.sep:
162 Path = ConversionPath
163 else:
164 Path = BasePath
165
166
167 @classmethod
169 """:return: the current working directory as a path object. """
170 return cls(_getcwd())
171
172
173
175 """:return: the parent directory of this Path or None if this is the root"""
176 parent = self.dirname()
177 if parent == self:
178 return None
179 return parent
180
181 - def children( self, predicate = lambda p: True, pattern = None ):
182 """:return: child paths as retrieved by queryiing the file system.
183 :note: files cannot have children, and willl return an empty array accordingly
184 :param predicate: return p if predicate( p ) returns True
185 :param pattern: list only elements that match the given simple pattern
186 i.e. *.*"""
187 try:
188 children = self.listdir( pattern )
189 except OSError:
190 return list()
191
192 return [ c for c in children if predicate( c ) ]
193
194
195
196
197
198 @classmethod
200 """Internal version returning a string only representing the non-recursively
201 expanded variable
202
203 :note: It is a slightly changed copy of the version in posixfile
204 as the windows version was implemented differently ( it expands
205 variables to an empty space which is undesireable )"""
206 if '$' not in path:
207 return path
208
209 i = 0
210 while True:
211 m = _varprog.search(path, i)
212 if not m:
213 break
214 i, j = m.span(0)
215 name = m.group(1)
216 if name.startswith('{') and name.endswith('}'):
217 name = name[1:-1]
218 if name in os.environ:
219 tail = path[j:]
220 path = path[:i] + os.environ[name]
221 i = len(path)
222 path += tail
223 else:
224 i = j
225
226
227 return path
228
229 @classmethod
238
239 isabs = os.path.isabs
247 basename = os.path.basename
248
250 """Expands all environment variables recursively"""
251 return type(self)(self._expandvars_deep(self))
252
254 """Expands all environment variables recursively, and raises ValueError
255 if the path still contains variables afterwards"""
256 rval = self.expandvars_deep()
257 if rval.containsvars():
258 raise ValueError("Failed to expand all environment variables in %r, got %r" % (self, rval))
259 return rval
260
262 """ Clean up a filename by calling expandvars() and expanduser()
263
264 This is commonly everything needed to clean up a filename
265 read from a configuration file, for example.
266
267 If you are not interested in trailing slashes, you should call
268 normpath() on the resulting Path as well.
269 """
270 return self.expandvars().expanduser()
271
273 """:return: True if this path contains environment variables"""
274 return self.find( '$' ) != -1
275
277 """:return: Copy of self with all variables expanded ( using `expand` )
278 non-recursively !
279
280 :raise ValueError: If we could not expand all environment variables as
281 their values where missing in the environment"""
282 rval = self.expand()
283 if str(rval) == str(self) and rval.containsvars():
284 raise ValueError("Failed to expand all environment variables in %r, got %r" % (self, rval))
285 return rval
286
288 """The same as path.basename(), but with one file extension stripped off.
289
290 For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz',
291 but path('/home/guido/python.tar.gz').namebase == 'python.tar'"""
292 base, ext = os.path.splitext(self.basename())
293 return base
294
296 """ The file extension, for example '.py'. """
297 f, ext = os.path.splitext(_base(self))
298 return ext
299
301 """ The drive specifier, for example 'C:'.
302 This is always empty on systems that don't use drive specifiers.
303 """
304 drive, r = os.path.splitdrive(self)
305 return self.__class__(drive)
306
308 """ p.splitpath() -> Return (p.parent(), p.basename()). """
309 parent, child = os.path.split(self)
310 return self.__class__(parent), child
311
313 """ p.splitdrive() -> Return (p.drive, <the rest of p>).
314
315 Split the drive specifier from this path. If there is
316 no drive specifier, p.drive is empty, so the return value
317 is simply (path(''), p). This is always the case on Unix.
318 """
319 drive, rel = os.path.splitdrive(self)
320 return self.__class__(drive), rel
321
322 - def splitext(self):
323 """ p.splitext() -> Return (p.stripext(), p.ext).
324
325 Split the filename extension from this path and return
326 the two parts. Either part may be empty.
327
328 The extension is everything from '.' to the end of the
329 last path segment. This has the property that if
330 (a, b) == p.splitext(), then a + b == p.
331 """
332 filename, ext = os.path.splitext(self)
333 return self.__class__(filename), ext
334
336 """ p.stripext() -> Remove one file extension from the path.
337
338 For example, path('/home/guido/python.tar.gz').stripext()
339 returns path('/home/guido/python.tar').
340 """
341 return self.splitext()[0]
342
343 if hasattr(os.path, 'splitunc'):
345 unc, rest = os.path.splitunc(self)
346 return self.__class__(unc), rest
347
349 unc, r = os.path.splitunc(self)
350 return self.__class__(unc)
351
353 """ Join two or more path components, adding a separator
354 character (os.sep) if needed. Returns a new path
355 object."""
356 return self.__class__(os.path.join(self, *args))
357
359 """ Return a list of the path components in this path.
360
361 The first item in the list will be a path. Its value will be
362 either os.curdir, os.pardir, empty, or the root directory of
363 this path (for example, '/' or 'C:\\'). The other items in
364 the list will be strings.
365
366 path.path.joinpath(\*result) can possibly yield the original path, depending
367 on the input."""
368 parts = list()
369 loc = self
370 while loc != os.curdir and loc != os.pardir:
371 prev = loc
372 loc, child = prev.splitpath()
373 if loc == prev:
374 break
375 parts.append(child)
376 parts.append(loc)
377 parts.reverse()
378 return parts
379
381 """ Return this path as a relative path,
382 originating from the current working directory.
383 """
384 return self.relpathto(os.getcwd())
385
387 """ Return a relative path from self to dest.
388
389 If there is no relative path from self to dest, for example if
390 they reside on different drives in Windows, then this returns
391 dest.abspath().
392 """
393
394
395 splitter = (os.name == 'nt' and _ossep) or self.sep
396 def commonprefix(m):
397 if not m: return ''
398 s1 = min(m)
399 s2 = max(m)
400 for i, c in enumerate(s1):
401 if c != s2[i]:
402 return s1[:i]
403 return s1
404
405
406 start_list = os.path.abspath(dest).split(splitter)
407 path_list = os.path.abspath(self._expandvars(self)).split(splitter)
408
409
410 i = len(commonprefix([start_list, path_list]))
411
412 rel_list = [os.pardir] * (len(start_list)-i) + path_list[i:]
413 if not rel_list:
414 return os.curdir
415 return self.__class__(os.path.join(*rel_list))
416
418 """ Return a relative path from dest to self"""
419 return self.__class__(dest).relpathto(self)
420
422 """:return: Version of self with all separators set to be 'sep'. The difference
423 to normpath is that it does not cut trailing separators"""
424 return self.__class__(self.replace(self.osep, self.sep))
425
427 """:return: A path using only slashes as path separator"""
428 return self.__class__(self.replace("\\", "/"))
429
431 r"""Convert the path separator to the type required by the current operating
432 system - on windows / becomes \ and on linux \ becomes /
433
434 :return: native version of self"""
435 s = "\\"
436 d = "/"
437 if sys.platform.startswith( "win" ):
438 s = "/"
439 d = "\\"
440 return Path( self.replace( s, d ) )
441
442
443
444
445
447 """return list of items in this directory.
448
449 Use D.files() or D.dirs() instead if you want a listing
450 of just files or just subdirectories.
451
452 The elements of the list are path objects.
453
454 With the optional 'pattern' argument, this only lists
455 items whose names match the given pattern.
456 """
457 names = os.listdir(self._expandvars(self))
458 if pattern is not None:
459 names = fnmatch.filter(names, pattern)
460 return [self / child for child in names]
461
462 - def dirs(self, pattern=None):
463 """ D.dirs() -> List of this directory's subdirectories.
464
465 The elements of the list are path objects.
466 This does not walk recursively into subdirectories
467 (but see path.walkdirs).
468
469 With the optional ``pattern`` argument, this only lists
470 directories whose names match the given pattern. For
471 example, d.dirs("build-\*").
472 """
473 return [p for p in self.listdir(pattern) if p.isdir()]
474
475 - def files(self, pattern=None):
476 """ D.files() -> List of the files in this directory.
477
478 The elements of the list are path objects.
479 This does not walk into subdirectories (see path.walkfiles).
480
481 With the optional ``pattern`` argument, this only lists files
482 whose names match the given pattern. For example,
483 d.files("\*.pyc").
484 """
485
486 return [p for p in self.listdir(pattern) if p.isfile()]
487
488 - def walk(self, pattern=None, errors='strict', predicate=lambda p: True):
489 """create iterator over files and subdirs, recursively.
490
491 The iterator yields path objects naming each child item of
492 this directory and its descendants.
493
494 It performs a depth-first traversal of the directory tree.
495 Each directory is returned just before all its children.
496
497 :param pattern: fnmatch compatible pattern or None
498 :param errors: controls behavior when an
499 error occurs. The default is 'strict', which causes an
500 exception. The other allowed values are 'warn', which
501 reports the error via log.warn(), and 'ignore'.
502 :param predicate: returns True for each Path p to be yielded by iterator
503 """
504 if errors not in ('strict', 'warn', 'ignore'):
505 raise ValueError("invalid errors parameter")
506
507 try:
508 childList = self.listdir()
509 except Exception:
510 if errors == 'ignore':
511 return
512 elif errors == 'warn':
513 log.warn(
514 "Unable to list directory '%s': %s"
515 % (self, sys.exc_info()[1]))
516 childList = list()
517 else:
518 raise
519
520
521
522 for child in childList:
523 if ( pattern is None or child.fnmatch(pattern) ) and predicate(child):
524 yield child
525
526 try:
527 isdir = child.isdir()
528 except Exception:
529 isdir = False
530 if errors == 'ignore':
531 pass
532 elif errors == 'warn':
533 log.warn(
534 "Unable to access '%s': %s"
535 % (child, sys.exc_info()[1]))
536 else:
537 raise
538
539
540
541 if not isdir:
542 continue
543
544 for item in child.walk(pattern, errors, predicate):
545 yield item
546
547
548
549 - def walkdirs(self, pattern=None, errors='strict', predicate=lambda p: True):
550 """ D.walkdirs() -> iterator over subdirs, recursively.
551 see `walk` for a parameter description """
552 pred = lambda p: p.isdir() and predicate(p)
553 return self.walk(pattern, errors, pred)
554
555 - def walkfiles(self, pattern=None, errors='strict', predicate=lambda p: True):
556 """ D.walkfiles() -> iterator over files in D, recursively.
557 see `walk` for a parameter description"""
558 pred = lambda p: p.isfile() and predicate(p)
559 return self.walk(pattern, errors, pred)
560
562 """ Return True if self.basename() matches the given pattern.
563
564 pattern - A filename pattern with wildcards,
565 for example "\*.py".
566 """
567 pathexpanded = self.expandvars()
568 return fnmatch.fnmatch(pathexpanded.basename(), pattern)
569
570 - def glob(self, pattern):
571 """ Return a list of path objects that match the pattern.
572
573 pattern - a path relative to this directory, with wildcards.
574
575 For example, path('/users').glob('*/bin/*') returns a list
576 of all the files users have in their bin directories.
577 """
578 cls = self.__class__
579 pathexpanded = self.expandvars()
580 return [cls(s) for s in glob.glob(_base(pathexpanded / pattern))]
581
582
583
584
585
586
587 - def open(self, *args, **kwargs):
590
592 """ Open this file, read all bytes, return them as a string. """
593 f = self.open('rb')
594 try:
595 return f.read()
596 finally:
597 f.close()
598
600 """ Open this file and write the given bytes to it.
601
602 Default behavior is to overwrite any existing file.
603 Call p.write_bytes(bytes, append=True) to append instead.
604 :return: self
605 """
606 if append:
607 mode = 'ab'
608 else:
609 mode = 'wb'
610 f = self.open(mode)
611 try:
612 f.write(bytes)
613 finally:
614 f.close()
615
616 return self
617
618 - def text(self, encoding=None, errors='strict'):
619 r""" Open this file, read it in, return the content as a string.
620
621 This uses "U" mode in Python 2.3 and later, so "\r\n" and "\r"
622 are automatically translated to '\n'.
623
624 Optional arguments:
625 * encoding - The Unicode encoding (or character set) of
626 the file. If present, the content of the file is
627 decoded and returned as a unicode object; otherwise
628 it is returned as an 8-bit str.
629 * errors - How to handle Unicode errors; see help(str.decode)
630 for the options. Default is 'strict'.
631 """
632 mode = 'U'
633
634 f = None
635 if encoding is None:
636 f = self.open(mode)
637 else:
638 f = codecs.open(self, 'r', encoding, errors)
639
640
641 try:
642 return f.read()
643 finally:
644 f.close()
645
646
647 - def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False):
648 r""" Write the given text to this file.
649
650 The default behavior is to overwrite any existing file;
651 to append instead, use the 'append=True' keyword argument.
652
653 There are two differences between path.write_text() and
654 path.write_bytes(): newline handling and Unicode handling.
655 See below.
656
657 **Parameters**:
658 - text - str/unicode - The text to be written.
659
660 - encoding - str - The Unicode encoding that will be used.
661 This is ignored if 'text' isn't a Unicode string.
662
663 - errors - str - How to handle Unicode encoding errors.
664 Default is 'strict'. See help(unicode.encode) for the
665 options. This is ignored if 'text' isn't a Unicode
666 string.
667
668 - linesep - keyword argument - str/unicode - The sequence of
669 characters to be used to mark end-of-line. The default is
670 os.linesep. You can also specify None; this means to
671 leave all newlines as they are in 'text'.
672
673 - append - keyword argument - bool - Specifies what to do if
674 the file already exists (True: append to the end of it;
675 False: overwrite it.) The default is False.
676
677
678 **Newline handling**:
679 - write_text() converts all standard end-of-line sequences
680 ("\n", "\r", and "\r\n") to your platforms default end-of-line
681 sequence (see os.linesep; on Windows, for example, the
682 end-of-line marker is "\r\n").
683
684 - If you don't like your platform's default, you can override it
685 using the "linesep=" keyword argument. If you specifically want
686 write_text() to preserve the newlines as-is, use "linesep=None".
687
688 - This applies to Unicode text the same as to 8-bit text, except
689 there are additional standard Unicode end-of-line sequences, check
690 the code to see them.
691
692 - (This is slightly different from when you open a file for
693 writing with fopen(filename, "w") in C or file(filename, "w")
694 in Python.)
695
696
697 **Unicode**:
698 If "text" isn't Unicode, then apart from newline handling, the
699 bytes are written verbatim to the file. The "encoding" and
700 'errors' arguments are not used and must be omitted.
701
702 If 'text' is Unicode, it is first converted to bytes using the
703 specified 'encoding' (or the default encoding if 'encoding'
704 isn't specified). The 'errors' argument applies only to this
705 conversion.
706
707 :return: self
708 """
709 bytes = ""
710 if isinstance(text, unicode):
711 if linesep is not None:
712
713
714 text = (text.replace(u'\r\n', u'\n')
715 .replace(u'\r\x85', u'\n')
716 .replace(u'\r', u'\n')
717 .replace(u'\x85', u'\n')
718 .replace(u'\u2028', u'\n'))
719 text = text.replace(u'\n', linesep)
720 if encoding is None:
721 encoding = sys.getdefaultencoding()
722 bytes = text.encode(encoding, errors)
723 else:
724
725
726 assert encoding is None
727
728 if linesep is not None:
729 text = (text.replace('\r\n', '\n')
730 .replace('\r', '\n'))
731 bytes = text.replace('\n', linesep)
732
733 self.write_bytes(bytes, append)
734 return self
735
736 - def write_lines(self, lines, encoding=None, errors='strict',
737 linesep=os.linesep, append=False):
738 r""" Write the given lines of text to this file.
739
740 By default this overwrites any existing file at this path.
741
742 This puts a platform-specific newline sequence on every line.
743 See 'linesep' below.
744
745 lines - A list of strings.
746
747 encoding - A Unicode encoding to use. This applies only if
748 'lines' contains any Unicode strings.
749
750 errors - How to handle errors in Unicode encoding. This
751 also applies only to Unicode strings.
752
753 linesep - The desired line-ending. This line-ending is
754 applied to every line. If a line already has any
755 standard line ending, that will be stripped off and
756 this will be used instead. The default is os.linesep,
757 which is platform-dependent ('\r\n' on Windows, '\n' on
758 Unix, etc.) Specify None to write the lines as-is,
759 like file.writelines().
760
761 Use the keyword argument append=True to append lines to the
762 file. The default is to overwrite the file. Warning:
763 When you use this with Unicode data, if the encoding of the
764 existing data in the file is different from the encoding
765 you specify with the encoding= parameter, the result is
766 mixed-encoding data, which can really confuse someone trying
767 to read the file later.
768
769 :return: self
770 """
771 if append:
772 mode = 'ab'
773 else:
774 mode = 'wb'
775 f = self.open(mode)
776 try:
777 for line in lines:
778 isUnicode = isinstance(line, unicode)
779 if linesep is not None:
780
781
782 if isUnicode:
783 if line[-2:] in (u'\r\n', u'\x0d\x85'):
784 line = line[:-2]
785 elif line[-1:] in (u'\r', u'\n',
786 u'\x85', u'\u2028'):
787 line = line[:-1]
788 else:
789 if line[-2:] == '\r\n':
790 line = line[:-2]
791 elif line[-1:] in ('\r', '\n'):
792 line = line[:-1]
793 line += linesep
794 if isUnicode:
795 if encoding is None:
796 encoding = sys.getdefaultencoding()
797 line = line.encode(encoding, errors)
798 f.write(line)
799 finally:
800 f.close()
801
802 return self
803
804 - def lines(self, encoding=None, errors='strict', retain=True):
805 r""" Open this file, read all lines, return them in a list.
806
807 Optional arguments:
808 * encoding: The Unicode encoding (or character set) of
809 the file. The default is None, meaning the content
810 of the file is read as 8-bit characters and returned
811 as a list of (non-Unicode) str objects.
812
813 * errors: How to handle Unicode errors; see help(str.decode)
814 for the options. Default is 'strict'
815
816 * retain: If true, retain newline characters; but all newline
817 character combinations ("\r", "\n", "\r\n") are
818 translated to "\n". If false, newline characters are
819 stripped off. Default is True.
820
821 This uses "U" mode in Python 2.3 and later.
822 """
823 if encoding is None and retain:
824 f = self.open(_textmode)
825 try:
826 return f.readlines()
827 finally:
828 f.close()
829 else:
830 return self.text(encoding, errors).splitlines(retain)
831
832 - def digest(self, hashobject):
833 """ Calculate the hash for this file using the given hashobject. It must
834 support the 'update' and 'digest' methods.
835
836 :note: This reads through the entire file.
837 """
838
839 f = self.open('rb')
840 try:
841 while True:
842 d = f.read(8192)
843 if not d:
844 break
845 hashobject.update(d)
846 finally:
847 f.close()
848
849
850 return hashobject.digest()
851
852
853
854
855
856 exists = lambda self: os.path.exists( self._expandvars(self) )
857 if hasattr(os.path, 'lexists'):
858 lexists = lambda self: os.path.lexists( self._expandvars(self) )
859 isdir = lambda self: os.path.isdir( self._expandvars(self) )
860 isfile = lambda self: os.path.isfile( self._expandvars(self) )
861 islink = lambda self: os.path.islink( self._expandvars(self) )
862 ismount = lambda self: os.path.ismount( self._expandvars(self) )
863
864 if hasattr(os.path, 'samefile'):
865 samefile = lambda self, other: os.path.samefile( self._expandvars(self), other )
866
867 atime = lambda self: os.path.getatime( self._expandvars(self) )
868 mtime = lambda self: os.path.getmtime( self._expandvars(self) )
869 if hasattr(os.path, 'getctime'):
870 ctime = lambda self: os.path.getctime( self._expandvars(self) )
871 size = lambda self: os.path.getsize( self._expandvars(self) )
872
873 if hasattr(os, 'access'):
875 """ Return true if current user has access to this path.
876
877 mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
878 """
879 return os.access(self._expandvars(self), mode)
880
882 """ Perform a stat() system call on this path. """
883 return os.stat(self._expandvars(self))
884
886 """ Like path.stat(), but do not follow symbolic links. """
887 return os.lstat(self._expandvars(self))
888
890 """ Return the name of the owner of this file or directory.
891
892 This follows symbolic links.
893
894 On Windows, this returns a name of the form ur'DOMAIN\User Name'.
895 On Windows, a group can own a file or directory.
896 """
897 if os.name == 'nt':
898 if win32security is None:
899 raise Exception("path.owner requires win32all to be installed")
900 desc = win32security.GetFileSecurity(
901 self, win32security.OWNER_SECURITY_INFORMATION)
902 sid = desc.GetSecurityDescriptorOwner()
903 account, domain, typecode = win32security.LookupAccountSid(None, sid)
904 return domain + u'\\' + account
905 else:
906 if pwd is None:
907 raise NotImplementedError("path.owner is not implemented on this platform.")
908 st = self.stat()
909 return pwd.getpwuid(st.st_uid).pw_name
910
911 if hasattr(os, 'statvfs'):
913 """ Perform a statvfs() system call on this path. """
914 return os.statvfs(self._expandvars(self))
915
916 if hasattr(os, 'pathconf'):
920
922 """:return: true if the file can be written to"""
923 if not self.exists():
924 return False
925
926 try:
927 fileobj = self.open( 'a' )
928 except:
929 return False
930 else:
931 fileobj.close()
932 return True
933
934
935
936
937
938
939
941 """ Set the access and modified times of this file.
942
943 :return: self"""
944 os.utime(self._expandvars(self), times)
945 return self
946
948 """Change file mode
949
950 :return: self"""
951 os.chmod(self._expandvars(self), mode)
952 return self
953
954 if hasattr(os, 'chown'):
955 - def chown(self, uid, gid):
956 """Change file ownership
957
958 :return: self"""
959 os.chown(self._expandvars(self), uid, gid)
960 return self
961
968
975
976
977
978
979
980 - def mkdir(self, mode=0777):
981 """Make this directory, fail if it already exists
982
983 :return: self"""
984 os.mkdir(self._expandvars(self), mode)
985 return self
986
988 """Smarter makedir, see os.makedirs
989
990 :return: self"""
991 os.makedirs(self._expandvars(self), mode)
992 return self
993
995 """Remove this empty directory
996
997 :return: self"""
998 os.rmdir(self._expandvars(self))
999 return self
1000
1002 """see os.removedirs
1003
1004 :return: self"""
1005 os.removedirs(self._expandvars(self))
1006 return self
1007
1008
1009
1010
1011
1012 - def touch(self, flags = os.O_WRONLY | os.O_CREAT, mode = 0666):
1013 """ Set the access/modified times of this file to the current time.
1014 Create the file if it does not exist.
1015
1016 :return: self
1017 """
1018 fd = os.open(self._expandvars(self), flags, mode)
1019 os.close(fd)
1020 os.utime(self._expandvars(self), None)
1021 return self
1022
1024 """Remove this file
1025
1026 :return: self"""
1027 os.remove(self._expandvars(self))
1028 return self
1029
1031 """unlink this file
1032
1033 :return: self"""
1034 os.unlink(self._expandvars(self))
1035 return self
1036
1037
1038
1039
1040
1041 if hasattr(os, 'link'):
1042 - def link(self, newpath):
1043 """ Create a hard link at 'newpath', pointing to this file.
1044
1045 :return: Path to newpath"""
1046 os.link(self._expandvars(self), newpath)
1047 return type(self)(newpath)
1048
1049
1050 if hasattr(os, 'symlink'):
1052 """ Create a symbolic link at 'newlink', pointing here.
1053
1054 :return: Path to newlink"""
1055 os.symlink(self._expandvars(self), newlink)
1056 return type(self)(newlink)
1057
1058 if hasattr(os, 'readlink'):
1060 """ Return the path to which this symbolic link points.
1061
1062 The result may be an absolute or a relative path.
1063 """
1064 return self.__class__(os.readlink(self._expandvars(self)))
1065
1067 """ Return the path to which this symbolic link points.
1068
1069 The result is always an absolute path.
1070 """
1071 p = self.readlink()
1072 if p.isabs():
1073 return p
1074 else:
1075 return (self.parent() / p).abspath()
1076
1077
1078
1079
1080
1082 """Copy self to dest
1083
1084 :return: Path to dest"""
1085 shutil.copyfile( self._expandvars(self), dest )
1086 return type(self)(dest)
1087
1089 """Copy our mode to dest
1090
1091 :return: Path to dest"""
1092 shutil.copymode( self._expandvars(self), dest )
1093 return type(self)(dest)
1094
1096 """Copy our stats to dest
1097
1098 :return: Path to dest"""
1099 shutil.copystat( self._expandvars(self), dest )
1100 return type(self)(dest)
1101
1102 - def copy(self, dest):
1103 """Copy data and source bits to dest
1104
1105 :return: Path to dest"""
1106 shutil.copy( self._expandvars(self), dest )
1107 return type(self)(dest)
1108
1110 """Shutil.copy2 self to dest
1111
1112 :return: Path to dest"""
1113 shutil.copy2( self._expandvars(self), dest )
1114 return type(self)(dest)
1115
1117 """Deep copy this file or directory to destination
1118
1119 :param kwargs: passed to shutil.copytree
1120 :return: Path to dest"""
1121 shutil.copytree( self._expandvars(self), dest, **kwargs )
1122 return type(self)(dest)
1123
1124 if hasattr(shutil, 'move'):
1125 - def move(self, dest):
1126 """Move self to dest
1127
1128 :return: Path to dest"""
1129 shutil.move( self._expandvars(self), dest )
1130 return type(self)(dest)
1131
1133 """Remove self recursively
1134
1135 :param kwargs: passed to shutil.rmtree
1136 :return: self"""
1137 shutil.rmtree( self._expandvars(self), **kwargs )
1138 return self
1139
1140
1141
1142
1143
1144 if hasattr(os, 'chroot'):
1146 """Change the root directory path
1147
1148 :return: self"""
1149 os.chroot(self._expandvars(self))
1150 return self
1151
1152 if hasattr(os, 'startfile'):
1154 """see os.startfile
1155
1156 :return: self"""
1157 os.startfile(self._expandvars(self))
1158 return self
1159
1160
1161
1162 _ossep = os.path.sep
1163 _oossep = (_ossep == "/" and "\\") or "/"
1168
1169
1170
1171
1172 BasePath = Path
1175 """On windows, python represents paths with backslashes, within maya though,
1176 these are slashes We want to keep the original representation, but allow
1177 the methods to work nonetheless."""
1180
1181 @classmethod
1186
1188 """:return: path with separators matching to our configuration"""
1189 return path.replace(self.osep, self.sep)
1190
1193
1196
1199
1203
1206
1209
1213
1214
1215 if hasattr(os.path, 'splitunc'):
1218
1221
1222
1223
1224
1225
1226
1227 -def make_path(path):
1228 """:return: A path instance of the correct type
1229 :note: use this constructor if you use the Path.set_separator method at runtime
1230 to assure you will always create instances of the actual type, and not only
1231 of the type you imported last"""
1232 return Path(path)
1233
1234
1235
1236
1237
1238 Path.set_separator(os.path.sep)
1239
1240