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