CARVIEW |
Select Language
HTTP/2 302
server: nginx
date: Fri, 18 Jul 2025 00:34:37 GMT
content-type: text/plain; charset=utf-8
content-length: 0
x-archive-redirect-reason: found capture at 20071208093036
location: https://web.archive.org/web/20071208093036/https://wiki.python.org/moin/AlternativePathModule
server-timing: captures_list;dur=0.548963, exclusion.robots;dur=0.018759, exclusion.robots.policy;dur=0.008725, esindex;dur=0.009391, cdx.remote;dur=27.920542, LoadShardBlock;dur=280.233996, PetaboxLoader3.datanode;dur=111.753652, PetaboxLoader3.resolve;dur=132.697618
x-app-server: wwwb-app216
x-ts: 302
x-tr: 333
server-timing: TR;dur=0,Tw;dur=0,Tc;dur=0
set-cookie: SERVER=wwwb-app216; path=/
x-location: All
x-rl: 0
x-na: 0
x-page-cache: MISS
server-timing: MISS
x-nid: DigitalOcean
referrer-policy: no-referrer-when-downgrade
permissions-policy: interest-cohort=()
HTTP/2 200
server: nginx
date: Fri, 18 Jul 2025 00:34:38 GMT
content-type: text/html;charset=utf-8
x-archive-orig-date: Sat, 08 Dec 2007 09:30:34 GMT
x-archive-orig-server: Apache/2.0.54 (Debian GNU/Linux) mod_fastcgi/2.4.2
x-archive-orig-connection: close
x-archive-guessed-content-type: text/html
x-archive-guessed-charset: utf-8
memento-datetime: Sat, 08 Dec 2007 09:30:36 GMT
link: ; rel="original", ; rel="timemap"; type="application/link-format", ; rel="timegate", ; rel="first memento"; datetime="Tue, 12 Sep 2006 20:17:23 GMT", ; rel="prev memento"; datetime="Tue, 07 Aug 2007 10:19:41 GMT", ; rel="memento"; datetime="Sat, 08 Dec 2007 09:30:36 GMT", ; rel="next memento"; datetime="Wed, 21 Oct 2009 04:30:22 GMT", ; rel="last memento"; datetime="Tue, 25 Jun 2024 22:58:44 GMT"
content-security-policy: default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: archive.org web.archive.org web-static.archive.org wayback-api.archive.org athena.archive.org analytics.archive.org pragma.archivelab.org wwwb-events.archive.org
x-archive-src: 52_1_20071208084132_crawl105-c/52_1_20071208092836_crawl107.arc.gz
server-timing: captures_list;dur=0.705007, exclusion.robots;dur=0.024272, exclusion.robots.policy;dur=0.010729, esindex;dur=0.014137, cdx.remote;dur=11.530282, LoadShardBlock;dur=135.580234, PetaboxLoader3.datanode;dur=182.019543, PetaboxLoader3.resolve;dur=102.371262, load_resource;dur=229.301430
x-app-server: wwwb-app216
x-ts: 200
x-tr: 673
server-timing: TR;dur=0,Tw;dur=0,Tc;dur=0
x-location: All
x-rl: 0
x-na: 0
x-page-cache: MISS
server-timing: MISS
x-nid: DigitalOcean
referrer-policy: no-referrer-when-downgrade
permissions-policy: interest-cohort=()
content-encoding: gzip
AlternativePathModule - PythonInfo Wiki
AlternativePathModule
1 # -*- coding: iso-8859-1 -*-
2 """ path.py - An object representing a path to a file or a directory.
3
4 Based on the path module by Jason Orendorff
5 (https://www.jorendorff.com/articles/python/path)
6
7 Written by Noam Raphael to show the idea of using a tuple instead of
8 a string, and to reduce the number of methods.
9
10 Currently only implements posix and nt paths - more can be added.
11
12 """
13
14 import os
15 import stat
16 import itertools
17 import fnmatch
18 import re
19 import string
20
21 class StatWrapper(object):
22 """ A wrapper around stat_result objects which gives additional properties.
23
24 This object is a wrapper around a stat_result object. It allows access
25 to all the original object's attributes, and adds a few convinient
26 properties, by using the stat module.
27
28 This object should have been a subclass posix.stat_result - it simply
29 isn't possible currently. This functionality may also be integrated into
30 the original type.
31 """
32
33 __slots__ = ['_stat']
34
35 def __init__(self, stat):
36 self._stat = stat
37
38 def __getattribute__(self, attr, *default):
39 try:
40 return object.__getattribute__(self, attr, *default)
41 except AttributeError:
42 return getattr(self._stat, attr, *default)
43
44 # Mode properties
45
46 @property
47 def isdir(self):
48 return stat.S_ISDIR(self.st_mode)
49 @property
50 def isfile(self):
51 return stat.S_ISREG(self.st_mode)
52 @property
53 def islink(self):
54 return stat.S_ISLNK(self.st_mode)
55
56 # Easier names properties
57
58 @property
59 def size(self):
60 return self.st_size
61 @property
62 def mtime(self):
63 return self.st_mtime
64 @property
65 def atime(self):
66 return self.st_atime
67 @property
68 def ctime(self):
69 return self.st_ctime
70
71
72 class BasePath(tuple):
73 """ The base, abstract, path type.
74
75 The OS-specific path types inherit from it.
76 """
77
78 # ----------------------------------------------------------------
79 # We start with methods which don't use system calls - they just
80 # manipulate paths.
81
82 class _BaseRoot(object):
83 """ Represents a start location for a path.
84
85 A Root is an object which may be the first element of a path tuple,
86 and represents from where to start the path.
87
88 On posix, there's only one: ROOT (singleton).
89 On nt, there are a few:
90 CURROOT - the root of the current drive (singleton)
91 Drive(letter) - the root of a specific drive
92 UnrootedDrive(letter) - the current working directory on a specific
93 drive
94 UNCRoot(host, mountpoint) - a UNC mount point
95
96 The class for each OS has its own root classes, which should inherit
97 from _OSBaseRoot.
98
99 str(root) should return the string name of the root. The string should
100 identify the root: two root elements with the same string should have
101 the same meaning. To allow meaningful sorting of path objects, root
102 objects can be compared to strings and other root objects. They are
103 smaller than all strings, and are compared with other root objects
104 according to their string name.
105
106 Every Root object should contain the "isabs" attribute, which is True
107 if changes in the current working directory won't change the meaning
108 of the root and False otherwise. (CURROOT and UnrootedDrive aren't
109 absolute)
110 If isabs is True, it should also implement the abspath() method, which
111 should return an absolute path object, equivalent to the root when the
112 call was made.
113 """
114 isabs = None
115
116 def abspath(self):
117 if self.abspath:
118 raise NotImplementedError, 'This root is already absolute'
119 else:
120 raise NotImplementedError, 'abspath is abstract'
121
122 def __str__(self):
123 raise NotImplementedError, '__str__ is abstract'
124
125 def __cmp__(self, other):
126 if isinstance(other, str):
127 return -1
128 elif isinstance(other, BasePath._BaseRoot):
129 return cmp(str(self), str(other))
130 else:
131 raise TypeError, 'Comparison not defined'
132
133 def __hash__(self):
134 # This allows path objects to be hashable
135 return hash(str(self))
136
137 # _OSBaseRoot should be the base of the OS-specific root classes, which
138 # should inherit from _BaseRoot
139 _OSBaseRoot = None
140
141 # These string constants should be filled by subclasses - they are real
142 # directory names
143 curdir = None
144 pardir = None
145
146 # These string constants are used by default implementations of methods,
147 # but are not part of the interface - the whole idea is for the interface
148 # to hide those details.
149 _sep = None
150 _altsep = None
151
152 @staticmethod
153 def _parse_str(pathstr):
154 # Concrete path classes should implement _parse_str to get a path
155 # string and return an iterable over path elements.
156 raise NotImplementedError, '_parse_str is abstract'
157
158 @staticmethod
159 def normcasestr(string):
160 """ Normalize the case of one path element.
161
162 This default implementation returns string unchanged. On
163 case-insensitive platforms, it returns the normalized string.
164 """
165 return string
166
167 # We make this method a property, to show that it doesn't use any
168 # system calls.
169 # Case-sensitive subclasses can redefine it to return self.
170 @property
171 def normcase(self):
172 """ Return an equivalent path with case-normalized elements. """
173 if self.isrel:
174 return self.__class__(self.normcasestr(element)
175 for element in self)
176 else:
177 def gen():
178 it = iter(self)
179 yield it.next()
180 for element in it:
181 yield self.normcasestr(element)
182 return self.__class__(gen())
183
184 @classmethod
185 def _normalize_elements(cls, elements):
186 # This method gets an iterable over path elements.
187 # It should return an iterator over normalized path elements -
188 # that is, curdir elements should be ignored.
189
190 for i, element in enumerate(elements):
191 if isinstance(element, str):
192 if element != cls.curdir:
193 if (not element or
194 cls._sep in element or
195 (cls._altsep and cls._altsep in element)):
196 # Those elements will cause path(str(x)) != x
197 raise ValueError, "Element %r is invalid" % element
198 yield element
199 elif i == 0 and isinstance(element, cls._OSBaseRoot):
200 yield element
201 else:
202 raise TypeError, "Element %r is of a wrong type" % element
203
204 def __new__(cls, arg=None):
205 """ Create a new path object.
206
207 If arg isn't given, an empty path, which represents the current
208 working directory, is returned.
209 If arg is a string, it is parsed into a logical path.
210 If arg is an iterable over path elements, a new path is created from
211 them.
212 """
213 if arg is None:
214 return tuple.__new__(cls)
215 elif type(arg) is cls:
216 return arg
217 elif isinstance(arg, str):
218 return tuple.__new__(cls, cls._parse_str(arg))
219 else:
220 return tuple.__new__(cls, cls._normalize_elements(arg))
221
222 def __init__(self, arg=None):
223 # Since paths are immutable, we can cache the string representation
224 self._cached_str = None
225
226 def _build_str(self):
227 # Return a string representation of self.
228 #
229 # This is a default implementation, which may be overriden by
230 # subclasses (form example, MacPath)
231 if not self:
232 return self.curdir
233 elif isinstance(self[0], self._OSBaseRoot):
234 return str(self[0]) + self._sep.join(self[1:])
235 else:
236 return self._sep.join(self)
237
238 def __str__(self):
239 """ Return a string representation of self. """
240 if self._cached_str is None:
241 self._cached_str = self._build_str()
242 return self._cached_str
243
244 def __repr__(self):
245 # We want path, not the real class name.
246 return 'path(%r)' % str(self)
247
248 @property
249 def isabs(self):
250 """ Return whether this path represent an absolute path.
251
252 An absolute path is a path whose meaning doesn't change when the
253 the current working directory changes.
254
255 (Note that this is not the same as "not self.isrelative")
256 """
257 return len(self) > 0 and \
isinstance(self[0], self._OSBaseRoot) and \
self[0].isabs
258
259 @property
260 def isrel(self):
261 """ Return whether this path represents a relative path.
262
263 A relative path is a path without a root element, so it can be
264 concatenated to other paths.
265
266 (Note that this is not the same as "not self.isabs")
267 """
268 return len(self) == 0 or \
not isinstance(self[0], self._OSBaseRoot)
269
270 # Wrap a few tuple methods to return path objects
271
272 def __add__(self, other):
273 other = self.__class__(other)
274 if not other.isrel:
275 raise ValueError, "Right operand should be a relative path"
276 return self.__class__(itertools.chain(self, other))
277
278 def __radd__(self, other):
279 if not self.isrel:
280 raise ValueError, "Right operand should be a relative path"
281 other = self.__class__(other)
282 return self.__class__(itertools.chain(other, self))
283
284 def __getslice__(self, *args):
285 return self.__class__(tuple.__getslice__(self, *args))
286
287 def __mul__(self, *args):
288 if not self.isrel:
289 raise ValueError, "Only relative paths can be multiplied"
290 return self.__class__(tuple.__mul__(self, *args))
291
292 def __rmul__(self, *args):
293 if not self.isrel:
294 raise ValueError, "Only relative paths can be multiplied"
295 return self.__class__(tuple.__rmul__(self, *args))
296
297 def __eq__(self, other):
298 return tuple.__eq__(self, self.__class__(other))
299 def __ge__(self, other):
300 return tuple.__ge__(self, self.__class__(other))
301 def __gt__(self, other):
302 return tuple.__gt__(self, self.__class__(other))
303 def __le__(self, other):
304 return tuple.__le__(self, self.__class__(other))
305 def __lt__(self, other):
306 return tuple.__lt__(self, self.__class__(other))
307 def __ne__(self, other):
308 return tuple.__ne__(self, self.__class__(other))
309
310
311 # ----------------------------------------------------------------
312 # Now come the methods which use system calls.
313
314 # --- Path transformation which use system calls
315
316 @classmethod
317 def cwd(cls):
318 return cls(os.getcwd())
319
320 def chdir(self):
321 return os.chdir(str(self))
322
323 def abspath(self):
324 if not self:
325 return self.cwd()
326 if isinstance(self[0], self._OSBaseRoot):
327 if self[0].isabs:
328 return self
329 else:
330 return self[0].abspath() + self[1:]
331 else:
332 return self.cwd() + self
333
334 def realpath(self):
335 return self.__class__(os.path.realpath(str(self)))
336
337 def relpathto(self, dst):
338 """ Return a relative path from self to dest.
339
340 This method examines self.realpath() and dest.realpath(). If
341 they have the same root element, a path in the form
342 path([path.pardir, path.pardir, ..., dir1, dir2, ...])
343 is returned. If they have different root elements,
344 dest.realpath() is returned.
345 """
346 src = self.realpath()
347 dst = self.__class__(dst).realpath()
348
349 if src[0] == dst[0]:
350 # They have the same root
351
352 # find the length of the equal prefix
353 i = 1
354 while i < len(src) and i < len(dst) and \
self.normcasestr(src[i]) == self.normcasestr(dst[i]):
355 i += 1
356
357 return [self.pardir] * (len(src) - i) + dst[i:]
358
359 else:
360 # They don't have the same root
361 return dst
362
363
364
365
366 # --- Expand
367
368 def expanduser(self):
369 return path(os.path.expanduser(str(self)))
370
371 def expandvars(self):
372 return path(os.path.expandvars(str(self)))
373
374
375 # --- Info about the path
376
377 def stat(self):
378 return StatWrapper(os.stat(str(self)))
379
380 def exists(self):
381 try:
382 self.stat()
383 except OSError:
384 return False
385 else:
386 return True
387
388 def isdir(self):
389 try:
390 return self.stat().isdir
391 except OSError:
392 return False
393
394 def isfile(self):
395 try:
396 return self.stat().isfile
397 except OSError:
398 return False
399
400 def lstat(self):
401 return StatWrapper(os.lstat(str(self)))
402
403 def lexists(self):
404 try:
405 self.lstat()
406 except OSError:
407 return False
408 else:
409 return True
410
411 def lisdir(self):
412 try:
413 return self.stat().lisdir
414 except OSError:
415 return False
416
417 def lisfile(self):
418 try:
419 return self.stat().lisfile
420 except OSError:
421 return False
422
423 def islink(self):
424 try:
425 return self.lstat().islink
426 except OSError:
427 return False
428
429 def ismount(self):
430 return os.path.ismount(str(self))
431
432 def access(self, mode):
433 """ Return true if current user has access to this path.
434
435 mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
436 """
437 return os.access(str(self), mode)
438
439 # Additional methods in subclasses:
440 # statvfs (PosixPath)
441 # pathconf (PosixPath, XXX MacPath)
442 # samefile (PosixPath, XXX MacPath)
443
444
445 # --- Modifying operations on files and directories
446
447 def utime(self, times):
448 """ Set the access and modified times of this file. """
449 os.utime(str(self), times)
450
451 def chmod(self, mode):
452 os.chmod(str(self), mode)
453
454 def rename(self, new):
455 os.rename(str(self), str(new))
456
457 # Additional methods in subclasses:
458 # chown (PosixPath, XXX MacPath)
459 # lchown (PosixPath, XXX MacPath)
460
461
462 # --- Create/delete operations on directories
463
464 def mkdir(self, mode=0777):
465 os.mkdir(str(self), mode)
466
467 def makedirs(self, mode=0777):
468 os.makedirs(str(self), mode)
469
470 def rmdir(self):
471 os.rmdir(str(self))
472
473 def removedirs(self, base=None):
474 """ Remove empty directories recursively.
475
476 If the directory is empty, remove it. If the parent directory becomes
477 empty, remove it too. Continue until a directory can't be removed,
478 because it's not empty or for other reasons.
479 If base is given, it should be a prefix of self. base won't be removed
480 even if it becomes empty.
481 Note: only directories explicitly listed in the path will be removed.
482 This means that if self is a relative path, predecesors of the
483 current working directory won't be removed.
484 """
485 if not self.stat().isdir:
486 raise OSError, 'removedirs only works on directories.'
487 base = self.__class__(base)
488 if base:
489 if not self[:len(base)] == base:
490 raise ValueError, 'base should be a prefix of self.'
491 stopat = len(base)
492 else:
493 stopat = 0
494 for i in xrange(len(self), stopat, -1):
495 try:
496 self[:i].rmdir()
497 except OSError:
498 break
499
500 def rmtree(self, *args):
501 return shutil.rmtree(str(self), *args)
502
503
504 # --- Modifying operations on files
505
506 def touch(self):
507 """ Set the access/modified times of this file to the current time.
508 Create the file if it does not exist.
509 """
510 fd = os.open(str(self), os.O_WRONLY | os.O_CREAT, 0666)
511 os.close(fd)
512 os.utime(str(self), None)
513
514 def remove(self):
515 os.remove(str(self))
516
517 def copy(self, dst, copystat=False):
518 """ Copy file from self to dst.
519
520 If copystat is False, copy data and mode bits ("cp self dst").
521 If copystat is True, copy data and all stat info ("cp -p self dst").
522
523 The destination may be a directory. If so, a file with the same base
524 name as self will be created in that directory.
525 """
526 dst = self.__class__(dst)
527 if dst.stat().isdir:
528 dst += self[-1]
529 shutil.copyfile(str(self), str(dst))
530 if copystat:
531 shutil.copystat(str(self), str(dst))
532 else:
533 shutil.copymode(str(self), str(dst))
534
535 def move(self, dst):
536 dst = self.__class__(dst)
537 return shutil.move(str(self), str(dst))
538
539
540 # --- Links
541
542 # In subclasses:
543 # link (PosixPath, XXX MacPath)
544 # writelink (PosixPath) - what about MacPath?
545 # readlink (PosixPath, XXX MacPath)
546 # readlinkpath (PosixPath, XXXMacPath)
547
548
549 # --- Extra
550
551 # In subclasses:
552 # mkfifo (PosixPath, XXX MacPath)
553 # mknod (PosixPath, XXX MacPath)
554 # chroot (PosixPath, XXX MacPath)
555 #
556 # startfile (NTPath)
557
558
559 # --- Globbing
560
561 # If the OS supports it, _id should be a function that gets a stat object
562 # and returns a unique id of a file.
563 # It the OS doesn't support it, it should be None.
564 _id = None
565
566 @staticmethod
567 def _match_element(comp_element, element):
568 # Does a filename match a compiled pattern element?
569 # The filename should be normcased.
570 if comp_element is None:
571 return True
572 elif isinstance(comp_element, str):
573 return comp_element == element
574 else:
575 return comp_element.match(element)
576
577 def _glob(cls, pth, comp_pattern, topdown, onlydirs, onlyfiles,
578 positions, on_path, stat):
579 """ The recursive function used by glob.
580
581 This version treats symbolic links as files. Broken symlinks won't be
582 listed.
583
584 pth is a dir in which we search.
585
586 comp_pattern is the compiled pattern. It's a sequence which should
587 consist of three kinds of elements:
588 * None - matches any number of subdirectories, including 0.
589 * a string - a normalized name, when exactly one name can be matched.
590 * a regexp - for testing if normalized names match.
591
592 positions is a sequence of positions on comp_pattern that children of
593 path may match. On the first call, if will be [0].
594
595 on_path is a set of inode identifiers on path, or None if circles
596 shouldn't be checked.
597
598 stat is the appropriate stat function - cls.stat or cls.lstat.
599 """
600
601 if len(positions) == 1 and isinstance(comp_pattern[positions[0]], str):
602 # We don't have to listdir if exactly one file name can match.
603 # Since we always stat the files, it's ok if the file doesn't exist.
604 listdir = [comp_pattern[positions[0]]]
605 else:
606 listdir = os.listdir(str(pth))
607 listdir.sort()
608
609 for subfile in listdir:
610 newpth = pth + subfile
611 # We don't strictly need to stat a file if we don't follow symlinks
612 # AND positions == [len(comp_pattern)-1] AND
613 # not isinstance(comp_pattern[-1], str), but do me a favour...
614 try:
615 st = stat(newpth)
616 except OSError:
617 continue
618 newpositions = []
619 subfilenorm = cls.normcasestr(subfile)
620
621 if topdown:
622 # If not topdown, it happens after we handle subdirs
623 if positions[-1] == len(comp_pattern) - 1:
624 if cls._match_element(comp_pattern[-1], subfilenorm):
625 if not ((onlydirs and not st.isdir) or
626 (onlyfiles and not st.isfile)):
627 yield newpth
628
629 for pos in reversed(positions):
630 if st.isdir:
631 comp_element = comp_pattern[pos]
632 if pos + 1 < len(comp_pattern):
633 if cls._match_element(comp_element, subfilenorm):
634 newpositions.append(pos + 1)
635 if comp_pattern[pos + 1] is None:
636 # We should stop at '..'
637 break
638 if comp_element is None:
639 newpositions.append(pos)
640 # We don't have to break - there are not supposed
641 # to be any positions before '..'.
642
643 if newpositions:
644 newpositions.reverse()
645
646 if on_path is not None:
647 newpath_id = cls._id(st)
648 if newpath_id in on_path:
649 raise OSError, "Circular path encountered"
650 on_path.add(newpath_id)
651
652 for x in cls._glob(newpth,
653 comp_pattern, topdown, onlydirs, onlyfiles,
654 newpositions, on_path, stat):
655 yield x
656
657 if on_path is not None:
658 on_path.remove(newpath_id)
659
660 if not topdown:
661 # If topdown, it happens after we handle subdirs
662 if positions[-1] == len(comp_pattern) - 1:
663 if cls._match_element(comp_pattern[-1], subfilenorm):
664 if not ((onlydirs and not st.isdir) or
665 (onlyfiles and not st.isfile)):
666 yield newpth
667
668 _magic_check = re.compile('[*?[]')
669
670 @classmethod
671 def _has_magic(cls, s):
672 return cls._magic_check.search(s) is not None
673
674 _cache = {}
675
676 @classmethod
677 def _compile_pattern(cls, pattern):
678 # Get a pattern, return the list of compiled pattern elements
679 # and the list of initial positions.
680 pattern = cls(pattern)
681 if not pattern.isrel:
682 raise ValueError, "pattern should be a relative path."
683
684 comp_pattern = []
685 last_was_none = False
686 for element in pattern:
687 element = cls.normcasestr(element)
688 if element == '**':
689 if not last_was_none:
690 comp_pattern.append(None)
691 else:
692 last_was_none = False
693 if not cls._has_magic(element):
694 comp_pattern.append(element)
695 else:
696 try:
697 r = cls._cache[element]
698 except KeyError:
699 r = re.compile(fnmatch.translate(element))
700 cls._cache[element] = r
701 comp_pattern.append(r)
702
703 if comp_pattern[0] is None and len(comp_pattern) > 1:
704 positions = [0, 1]
705 else:
706 positions = [0]
707
708 return comp_pattern, positions
709
710 def match(self, pattern):
711 """ Return whether self matches the given pattern.
712
713 pattern has the same meaning as in the glob method.
714 self should be relative.
715
716 This method doesn't use any system calls.
717 """
718 if not self.isrel:
719 raise ValueError, "self must be a relative path"
720 comp_pattern, positions = self._compile_pattern(pattern)
721
722 for element in self.normcase:
723 newpositions = []
724 for pos in reversed(positions):
725 if pos == len(comp_pattern):
726 # We matched the pattern but the path isn't finished -
727 # too bad
728 continue
729 comp_element = comp_pattern[pos]
730 if self._match_element(comp_element, element):
731 newpositions.append(pos + 1)
732 if comp_element is None:
733 newpositions.append(pos)
734 # No need to continue after a '**'
735 break
736 newpositions.reverse()
737 positions = newpositions
738 if not positions:
739 # No point in carrying on
740 break
741
742 return (len(comp_pattern) in positions)
743
744 def glob(self, pattern='*', topdown=True, onlydirs=False, onlyfiles=False):
745 """ Return an iterator over all files in self matching pattern.
746
747 pattern should be a relative path, which may include wildcards.
748 In addition to the regular shell wildcards, you can use '**', which
749 matches any number of directories, including 0.
750
751 If topdown is True (the default), a directory is yielded before its
752 descendents. If it's False, a directory is yielded after its
753 descendents.
754
755 If onlydirs is True, only directories will be yielded. If onlyfiles
756 is True, only regular files will be yielded.
757
758 This method treats symbolic links as regular files. Broken symlinks
759 won't be yielded.
760 """
761
762 if onlydirs and onlyfiles:
763 raise ValueError, \
"Only one of onlydirs and onlyfiles can be specified."
764
765 comp_pattern, positions = self._compile_pattern(pattern)
766
767 if self._id is not None and None in comp_pattern:
768 on_path = set([self._id(self.stat())])
769 else:
770 on_path = None
771
772 for x in self._glob(self, comp_pattern, topdown, onlydirs, onlyfiles,
773 positions, on_path, self.__class__.stat):
774 yield x
775
776 def lglob(self, pattern='*', topdown=True, onlydirs=False, onlyfiles=False):
777 """ Return an iterator over all files in self matching pattern.
778
779 pattern should be a relative path, which may include wildcards.
780 In addition to the regular shell wildcards, you can use '**', which
781 matches any number of directories, including 0.
782
783 If topdown is True (the default), a directory is yielded before its
784 descendents. If it's False, a directory is yielded after its
785 descendents.
786
787 If onlydirs is True, only directories will be yielded. If onlyfiles
788 is True, only regular files will be yielded.
789
790 This method treats symbolic links as special files - they won't be
791 followed, and they will be yielded even if they're broken.
792 """
793
794 if onlydirs and onlyfiles:
795 raise ValueError, \
"Only one of onlydirs and onlyfiles can be specified."
796
797 comp_pattern, positions = self._compile_pattern(pattern)
798
799 for x in self._glob(self, comp_pattern, topdown, onlydirs, onlyfiles,
800 positions, None, self.__class__.lstat):
801 yield x
802
803
804 class PosixPath(BasePath):
805 """ Represents POSIX paths. """
806
807 class _PosixRoot(BasePath._BaseRoot):
808 """ Represents the filesystem root (/).
809
810 There's only one root on posix systems, so this is a singleton.
811 """
812 instance = None
813 def __new__(cls):
814 if cls.instance is None:
815 instance = object.__new__(cls)
816 cls.instance = instance
817 return cls.instance
818
819 def __str__(self):
820 return '/'
821
822 def __repr__(self):
823 return 'path.ROOT'
824
825 isabs = True
826
827 _OSBaseRoot = _PosixRoot
828
829 ROOT = _PosixRoot()
830
831 # Public constants
832 curdir = '.'
833 pardir = '..'
834
835 # Private constants
836 _sep = '/'
837 _altsep = None
838
839 @classmethod
840 def _parse_str(cls, pathstr):
841 # get a path string and return an iterable over path elements.
842 if pathstr.startswith('/'):
843 if pathstr.startswith('//') and not pathstr.startswith('///'):
844 # Two initial slashes have application-specific meaning
845 # in POSIX, and it's not supported currently.
846 raise NotImplementedError, \
"Paths with two leading slashes aren't supported."
847 yield cls.ROOT
848 for element in pathstr.split('/'):
849 if element == '' or element == cls.curdir:
850 continue
851 # '..' aren't specially treated, since popping the last
852 # element isn't correct if the last element was a symbolic
853 # link.
854 yield element
855
856
857 # POSIX-specific methods
858
859
860 # --- Info about the path
861
862 def statvfs(self):
863 """ Perform a statvfs() system call on this path. """
864 return os.statvfs(str(self))
865
866 def pathconf(self, name):
867 return os.pathconf(str(self), name)
868
869 def samefile(self, other):
870 other = self.__class__(other)
871 s1 = self.stat()
872 s2 = other.stat()
873 return s1.st_ino == s2.st_ino and \
s1.st_dev == s2.st_dev
874
875
876 # --- Modifying operations on files and directories
877
878 def chown(self, uid=None, gid=None):
879 if uid is None:
880 uid = -1
881 if gid is None:
882 gid = -1
883 return os.chown(str(self), uid, gid)
884
885 def lchown(self, uid=None, gid=None):
886 if uid is None:
887 uid = -1
888 if gid is None:
889 gid = -1
890 return os.lchown(str(self), uid, gid)
891
892
893 # --- Links
894
895 def link(self, newpath):
896 """ Create a hard link at 'newpath', pointing to this file. """
897 os.link(str(self), str(newpath))
898
899 def writelink(self, src):
900 """ Create a symbolic link at self, pointing to src.
901
902 src may be any string. Note that if it's a relative path, it
903 will be interpreted relative to self, not relative to the current
904 working directory.
905 """
906 os.symlink(str(src), str(self))
907
908 def readlink(self):
909 """ Return the path to which this symbolic link points.
910
911 The result is a string, which may be an absolute path, a
912 relative path (which should be interpreted relative to self[:-1]),
913 or any arbitrary string.
914 """
915 return os.readlink(str(self))
916
917 def readlinkpath(self):
918 """ Return the path to which this symbolic link points. """
919 linkpath = self.__class__(self.readlink())
920 if linkpath.isrel:
921 return self + linkpath
922 else:
923 return linkpath
924
925
926 # --- Extra
927
928 def mkfifo(self, *args):
929 return os.mkfifo(str(self), *args)
930
931 def mknod(self, *args):
932 return os.mknod(str(self), *args)
933
934 def chroot(self):
935 return os.chroot(str(self))
936
937
938 # --- Globbing
939
940 @staticmethod
941 def _id(stat):
942 return (stat.st_ino, stat.st_dev)
943
944
945 class NTPath(BasePath):
946 """ Represents paths on Windows operating systems. """
947
948 class _NTBaseRoot(BasePath._BaseRoot):
949 """ The base class of all Windows root classes. """
950 pass
951
952 _OSBaseRoot = _NTBaseRoot
953
954 class _CurRootType(_NTBaseRoot):
955 """ Represents the root of the current working drive.
956
957 This class is a singleton. It represents the root of the current
958 working drive - paths starting with '\'.
959 """
960 instance = None
961 def __new__(cls):
962 if cls.instance is None:
963 instance = object.__new__(cls)
964 cls.instance = instance
965 return cls.instance
966
967 def __str__(self):
968 return '\\'
969
970 def __repr__(self):
971 return 'path.CURROOT'
972
973 isabs = False
974
975 def abspath(self):
976 from nt import _getfullpathname
977 return NTPath(_getfullpathname(str(self)))
978
979 CURROOT = _CurRootType()
980
981 class Drive(_NTBaseRoot):
982 """ Represents the root of a specific drive. """
983 def __init__(self, letter):
984 # Drive letter is normalized - we don't lose any information
985 if len(letter) != 1 or letter not in string.letters:
986 raise ValueError, 'Should get one letter'
987 self._letter = letter.lower()
988
989 @property
990 def letter(self):
991 # We use a property because we want the object to be immutable.
992 return self._letter
993
994 def __str__(self):
995 return '%s:\\' % self.letter
996
997 def __repr__(self):
998 return 'path.Drive(%r)' % self.letter
999
1000 isabs = True
1001
1002 class UnrootedDrive(_NTBaseRoot):
1003 """ Represents the current working directory on a specific drive. """
1004 def __init__(self, letter):
1005 # Drive letter is normalized - we don't lose any information
1006 if len(letter) != 1 or letter not in string.letters:
1007 raise ValueError, 'Should get one letter'
1008 self._letter = letter.lower()
1009
1010 @property
1011 def letter(self):
1012 # We use a property because we want the object to be immutable.
1013 return self._letter
1014
1015 def __str__(self):
1016 return '%s:' % self.letter
1017
1018 def __repr__(self):
1019 return 'path.UnrootedDrive(%r)' % self.letter
1020
1021 isabs = False
1022
1023 def abspath(self):
1024 from nt import _getfullpathname
1025 return NTPath(_getfullpathname(str(self)))
1026
1027 class UNCRoot(_NTBaseRoot):
1028 """ Represents a UNC mount point. """
1029 def __init__(self, host, mountpoint):
1030 # Host and mountpoint are normalized - we don't lose any information
1031 self._host = host.lower()
1032 self._mountpoint = mountpoint.lower()
1033
1034 @property
1035 def host(self):
1036 # We use a property because we want the object to be immutable.
1037 return self._host
1038
1039 @property
1040 def mountpoint(self):
1041 # We use a property because we want the object to be immutable.
1042 return self._mountpoint
1043
1044 def __str__(self):
1045 return '\\\\%s\\%s\\' % (self.host, self.mountpoint)
1046
1047 def __repr__(self):
1048 return 'path.UNCRoot(%r, %r)' % (self.host, self.mountpoint)
1049
1050 isabs = True
1051
1052
1053 # Public constants
1054 curdir = '.'
1055 pardir = '..'
1056
1057 # Private constants
1058 _sep = '\\'
1059 _altsep = '/'
1060
1061 @staticmethod
1062 def normcasestr(string):
1063 """ Normalize the case of one path element.
1064
1065 On Windows, this returns string.lower()
1066 """
1067 return string.lower()
1068
1069 @classmethod
1070 def _parse_str(cls, pathstr):
1071 # get a path string and return an iterable over path elements.
1072
1073 # First, replace all backslashes with slashes.
1074 # I know that it should have been the other way round, but I can't
1075 # stand all those escapes.
1076
1077 pathstr = pathstr.replace('\\', '/')
1078
1079 # Handle the root element
1080
1081 if pathstr.startswith('/'):
1082 if pathstr.startswith('//'):
1083 # UNC Path
1084 if pathstr.startswith('///'):
1085 raise ValueError, \
"Paths can't start with more than two slashes"
1086 index = pathstr.find('/', 2)
1087 if index == -1:
1088 raise ValueError, \
"UNC host name should end with a slash"
1089 index2 = index+1
1090 while pathstr[index2:index2+1] == '/':
1091 index2 += 1
1092 if index2 == len(pathstr):
1093 raise ValueError, \
"UNC mount point is empty"
1094 index3 = pathstr.find('/', index2)
1095 if index3 == -1:
1096 index3 = len(pathstr)
1097 yield cls.UNCRoot(pathstr[2:index], pathstr[index2:index3])
1098 pathstr = pathstr[index3:]
1099 else:
1100 # CURROOT
1101 yield cls.CURROOT
1102 else:
1103 if pathstr[1:2] == ':':
1104 if pathstr[2:3] == '/':
1105 # Rooted drive
1106 yield cls.Drive(pathstr[0])
1107 pathstr = pathstr[3:]
1108 else:
1109 # Unrooted drive
1110 yield cls.UnrootedDrive(pathstr[0])
1111 pathstr = pathstr[2:]
1112
1113 # Handle all other elements
1114
1115 for element in pathstr.split('/'):
1116 if element == '' or element == cls.curdir:
1117 continue
1118 # We don't treat pardir specially, since in the presence of
1119 # links there's nothing to do about them.
1120 # Windows doesn't have links, but why not keep path handling
1121 # similiar?
1122 yield element
1123
1124
1125 # NT-specific methods
1126
1127 # --- Extra
1128
1129 def startfile(self):
1130 return os.startfile(str(self))
1131
1132 if os.name == 'posix':
1133 path = PosixPath
1134 elif os.name == 'nt':
1135 path = NTPath
1136 else:
1137 raise NotImplementedError, \
"The path object is currently not implemented for OS %r" % os.name
EditText (last edited 2006-05-02 14:01:48 by NoamRaphael)
- Login
- Navigation
- Actions
- Your recent pages