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