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