##// END OF EJS Templates
Update path.py to version 2.2.
walter.doerwald -
Show More

The requested changes are too big and content was truncated. Show full diff

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