1import fnmatch 2import functools 3import io 4import ntpath 5import os 6import posixpath 7import re 8import sys 9import time 10from collections import Sequence 11from contextlib import contextmanager 12from errno import EINVAL, ENOENT 13from operator import attrgetter 14from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO 15try: 16 from urllib import quote as urlquote, quote as urlquote_from_bytes 17except ImportError: 18 from urllib.parse import quote as urlquote, quote_from_bytes as urlquote_from_bytes 19 20 21try: 22 intern = intern 23except NameError: 24 intern = sys.intern 25try: 26 basestring = basestring 27except NameError: 28 basestring = str 29 30supports_symlinks = True 31try: 32 import nt 33except ImportError: 34 nt = None 35else: 36 if sys.getwindowsversion()[:2] >= (6, 0) and sys.version_info >= (3, 2): 37 from nt import _getfinalpathname 38 else: 39 supports_symlinks = False 40 _getfinalpathname = None 41 42 43__all__ = [ 44 "PurePath", "PurePosixPath", "PureWindowsPath", 45 "Path", "PosixPath", "WindowsPath", 46 ] 47 48# 49# Internals 50# 51 52_py2 = sys.version_info < (3,) 53_py2_fs_encoding = 'ascii' 54 55def _py2_fsencode(parts): 56 # py2 => minimal unicode support 57 return [part.encode(_py2_fs_encoding) if isinstance(part, unicode) 58 else part for part in parts] 59 60def _is_wildcard_pattern(pat): 61 # Whether this pattern needs actual matching using fnmatch, or can 62 # be looked up directly as a file. 63 return "*" in pat or "?" in pat or "[" in pat 64 65 66class _Flavour(object): 67 """A flavour implements a particular (platform-specific) set of path 68 semantics.""" 69 70 def __init__(self): 71 self.join = self.sep.join 72 73 def parse_parts(self, parts): 74 if _py2: 75 parts = _py2_fsencode(parts) 76 parsed = [] 77 sep = self.sep 78 altsep = self.altsep 79 drv = root = '' 80 it = reversed(parts) 81 for part in it: 82 if not part: 83 continue 84 if altsep: 85 part = part.replace(altsep, sep) 86 drv, root, rel = self.splitroot(part) 87 if sep in rel: 88 for x in reversed(rel.split(sep)): 89 if x and x != '.': 90 parsed.append(intern(x)) 91 else: 92 if rel and rel != '.': 93 parsed.append(intern(rel)) 94 if drv or root: 95 if not drv: 96 # If no drive is present, try to find one in the previous 97 # parts. This makes the result of parsing e.g. 98 # ("C:", "/", "a") reasonably intuitive. 99 for part in it: 100 drv = self.splitroot(part)[0] 101 if drv: 102 break 103 break 104 if drv or root: 105 parsed.append(drv + root) 106 parsed.reverse() 107 return drv, root, parsed 108 109 def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2): 110 """ 111 Join the two paths represented by the respective 112 (drive, root, parts) tuples. Return a new (drive, root, parts) tuple. 113 """ 114 if root2: 115 if not drv2 and drv: 116 return drv, root2, [drv + root2] + parts2[1:] 117 elif drv2: 118 if drv2 == drv or self.casefold(drv2) == self.casefold(drv): 119 # Same drive => second path is relative to the first 120 return drv, root, parts + parts2[1:] 121 else: 122 # Second path is non-anchored (common case) 123 return drv, root, parts + parts2 124 return drv2, root2, parts2 125 126 127class _WindowsFlavour(_Flavour): 128 # Reference for Windows paths can be found at 129 # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx 130 131 sep = '\\' 132 altsep = '/' 133 has_drv = True 134 pathmod = ntpath 135 136 is_supported = (nt is not None) 137 138 drive_letters = ( 139 set(chr(x) for x in range(ord('a'), ord('z') + 1)) | 140 set(chr(x) for x in range(ord('A'), ord('Z') + 1)) 141 ) 142 ext_namespace_prefix = '\\\\?\\' 143 144 reserved_names = ( 145 set(['CON', 'PRN', 'AUX', 'NUL']) | 146 set(['COM%d' % i for i in range(1, 10)]) | 147 set(['LPT%d' % i for i in range(1, 10)]) 148 ) 149 150 # Interesting findings about extended paths: 151 # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported 152 # but '\\?\c:/a' is not 153 # - extended paths are always absolute; "relative" extended paths will 154 # fail. 155 156 def splitroot(self, part, sep=sep): 157 first = part[0:1] 158 second = part[1:2] 159 if (second == sep and first == sep): 160 # XXX extended paths should also disable the collapsing of "." 161 # components (according to MSDN docs). 162 prefix, part = self._split_extended_path(part) 163 first = part[0:1] 164 second = part[1:2] 165 else: 166 prefix = '' 167 third = part[2:3] 168 if (second == sep and first == sep and third != sep): 169 # is a UNC path: 170 # vvvvvvvvvvvvvvvvvvvvv root 171 # \\machine\mountpoint\directory\etc\... 172 # directory ^^^^^^^^^^^^^^ 173 index = part.find(sep, 2) 174 if index != -1: 175 index2 = part.find(sep, index + 1) 176 # a UNC path can't have two slashes in a row 177 # (after the initial two) 178 if index2 != index + 1: 179 if index2 == -1: 180 index2 = len(part) 181 if prefix: 182 return prefix + part[1:index2], sep, part[index2+1:] 183 else: 184 return part[:index2], sep, part[index2+1:] 185 drv = root = '' 186 if second == ':' and first in self.drive_letters: 187 drv = part[:2] 188 part = part[2:] 189 first = third 190 if first == sep: 191 root = first 192 part = part.lstrip(sep) 193 return prefix + drv, root, part 194 195 def casefold(self, s): 196 return s.lower() 197 198 def casefold_parts(self, parts): 199 return [p.lower() for p in parts] 200 201 def resolve(self, path): 202 s = str(path) 203 if not s: 204 return os.getcwd() 205 if _getfinalpathname is not None: 206 return self._ext_to_normal(_getfinalpathname(s)) 207 # Means fallback on absolute 208 return None 209 210 def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix): 211 prefix = '' 212 if s.startswith(ext_prefix): 213 prefix = s[:4] 214 s = s[4:] 215 if s.startswith('UNC\\'): 216 prefix += s[:3] 217 s = '\\' + s[3:] 218 return prefix, s 219 220 def _ext_to_normal(self, s): 221 # Turn back an extended path into a normal DOS-like path 222 return self._split_extended_path(s)[1] 223 224 def is_reserved(self, parts): 225 # NOTE: the rules for reserved names seem somewhat complicated 226 # (e.g. r"..\NUL" is reserved but not r"foo\NUL"). 227 # We err on the side of caution and return True for paths which are 228 # not considered reserved by Windows. 229 if not parts: 230 return False 231 if parts[0].startswith('\\\\'): 232 # UNC paths are never reserved 233 return False 234 return parts[-1].partition('.')[0].upper() in self.reserved_names 235 236 def make_uri(self, path): 237 # Under Windows, file URIs use the UTF-8 encoding. 238 drive = path.drive 239 if len(drive) == 2 and drive[1] == ':': 240 # It's a path on a local drive => 'file:///c:/a/b' 241 rest = path.as_posix()[2:].lstrip('/') 242 return 'file:///%s/%s' % ( 243 drive, urlquote_from_bytes(rest.encode('utf-8'))) 244 else: 245 # It's a path on a network drive => 'file://host/share/a/b' 246 return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8')) 247 248 249class _PosixFlavour(_Flavour): 250 sep = '/' 251 altsep = '' 252 has_drv = False 253 pathmod = posixpath 254 255 is_supported = (os.name != 'nt') 256 257 def splitroot(self, part, sep=sep): 258 if part and part[0] == sep: 259 stripped_part = part.lstrip(sep) 260 # According to POSIX path resolution: 261 # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11 262 # "A pathname that begins with two successive slashes may be 263 # interpreted in an implementation-defined manner, although more 264 # than two leading slashes shall be treated as a single slash". 265 if len(part) - len(stripped_part) == 2: 266 return '', sep * 2, stripped_part 267 else: 268 return '', sep, stripped_part 269 else: 270 return '', '', part 271 272 def casefold(self, s): 273 return s 274 275 def casefold_parts(self, parts): 276 return parts 277 278 def resolve(self, path): 279 sep = self.sep 280 accessor = path._accessor 281 seen = {} 282 def _resolve(path, rest): 283 if rest.startswith(sep): 284 path = '' 285 286 for name in rest.split(sep): 287 if not name or name == '.': 288 # current dir 289 continue 290 if name == '..': 291 # parent dir 292 path, _, _ = path.rpartition(sep) 293 continue 294 newpath = path + sep + name 295 if newpath in seen: 296 # Already seen this path 297 path = seen[newpath] 298 if path is not None: 299 # use cached value 300 continue 301 # The symlink is not resolved, so we must have a symlink loop. 302 raise RuntimeError("Symlink loop from %r" % newpath) 303 # Resolve the symbolic link 304 try: 305 target = accessor.readlink(newpath) 306 except OSError as e: 307 if e.errno != EINVAL: 308 raise 309 # Not a symlink 310 path = newpath 311 else: 312 seen[newpath] = None # not resolved symlink 313 path = _resolve(path, target) 314 seen[newpath] = path # resolved symlink 315 316 return path 317 # NOTE: according to POSIX, getcwd() cannot contain path components 318 # which are symlinks. 319 base = '' if path.is_absolute() else os.getcwd() 320 return _resolve(base, str(path)) or sep 321 322 def is_reserved(self, parts): 323 return False 324 325 def make_uri(self, path): 326 # We represent the path using the local filesystem encoding, 327 # for portability to other applications. 328 bpath = bytes(path) 329 return 'file://' + urlquote_from_bytes(bpath) 330 331 332_windows_flavour = _WindowsFlavour() 333_posix_flavour = _PosixFlavour() 334 335 336class _Accessor: 337 """An accessor implements a particular (system-specific or not) way of 338 accessing paths on the filesystem.""" 339 340 341class _NormalAccessor(_Accessor): 342 343 def _wrap_strfunc(strfunc): 344 @functools.wraps(strfunc) 345 def wrapped(pathobj, *args): 346 return strfunc(str(pathobj), *args) 347 return staticmethod(wrapped) 348 349 def _wrap_binary_strfunc(strfunc): 350 @functools.wraps(strfunc) 351 def wrapped(pathobjA, pathobjB, *args): 352 return strfunc(str(pathobjA), str(pathobjB), *args) 353 return staticmethod(wrapped) 354 355 stat = _wrap_strfunc(os.stat) 356 357 lstat = _wrap_strfunc(os.lstat) 358 359 open = _wrap_strfunc(os.open) 360 361 listdir = _wrap_strfunc(os.listdir) 362 363 chmod = _wrap_strfunc(os.chmod) 364 365 if hasattr(os, "lchmod"): 366 lchmod = _wrap_strfunc(os.lchmod) 367 else: 368 def lchmod(self, pathobj, mode): 369 raise NotImplementedError("lchmod() not available on this system") 370 371 mkdir = _wrap_strfunc(os.mkdir) 372 373 unlink = _wrap_strfunc(os.unlink) 374 375 rmdir = _wrap_strfunc(os.rmdir) 376 377 rename = _wrap_binary_strfunc(os.rename) 378 379 if sys.version_info >= (3, 3): 380 replace = _wrap_binary_strfunc(os.replace) 381 382 if nt: 383 if supports_symlinks: 384 symlink = _wrap_binary_strfunc(os.symlink) 385 else: 386 def symlink(a, b, target_is_directory): 387 raise NotImplementedError("symlink() not available on this system") 388 else: 389 # Under POSIX, os.symlink() takes two args 390 @staticmethod 391 def symlink(a, b, target_is_directory): 392 return os.symlink(str(a), str(b)) 393 394 utime = _wrap_strfunc(os.utime) 395 396 # Helper for resolve() 397 def readlink(self, path): 398 return os.readlink(path) 399 400 401_normal_accessor = _NormalAccessor() 402 403 404# 405# Globbing helpers 406# 407 408@contextmanager 409def _cached(func): 410 try: 411 func.__cached__ 412 yield func 413 except AttributeError: 414 cache = {} 415 def wrapper(*args): 416 try: 417 return cache[args] 418 except KeyError: 419 value = cache[args] = func(*args) 420 return value 421 wrapper.__cached__ = True 422 try: 423 yield wrapper 424 finally: 425 cache.clear() 426 427def _make_selector(pattern_parts): 428 pat = pattern_parts[0] 429 child_parts = pattern_parts[1:] 430 if pat == '**': 431 cls = _RecursiveWildcardSelector 432 elif '**' in pat: 433 raise ValueError("Invalid pattern: '**' can only be an entire path component") 434 elif _is_wildcard_pattern(pat): 435 cls = _WildcardSelector 436 else: 437 cls = _PreciseSelector 438 return cls(pat, child_parts) 439 440if hasattr(functools, "lru_cache"): 441 _make_selector = functools.lru_cache()(_make_selector) 442 443 444class _Selector: 445 """A selector matches a specific glob pattern part against the children 446 of a given path.""" 447 448 def __init__(self, child_parts): 449 self.child_parts = child_parts 450 if child_parts: 451 self.successor = _make_selector(child_parts) 452 else: 453 self.successor = _TerminatingSelector() 454 455 def select_from(self, parent_path): 456 """Iterate over all child paths of `parent_path` matched by this 457 selector. This can contain parent_path itself.""" 458 path_cls = type(parent_path) 459 is_dir = path_cls.is_dir 460 exists = path_cls.exists 461 listdir = parent_path._accessor.listdir 462 return self._select_from(parent_path, is_dir, exists, listdir) 463 464 465class _TerminatingSelector: 466 467 def _select_from(self, parent_path, is_dir, exists, listdir): 468 yield parent_path 469 470 471class _PreciseSelector(_Selector): 472 473 def __init__(self, name, child_parts): 474 self.name = name 475 _Selector.__init__(self, child_parts) 476 477 def _select_from(self, parent_path, is_dir, exists, listdir): 478 if not is_dir(parent_path): 479 return 480 path = parent_path._make_child_relpath(self.name) 481 if exists(path): 482 for p in self.successor._select_from(path, is_dir, exists, listdir): 483 yield p 484 485 486class _WildcardSelector(_Selector): 487 488 def __init__(self, pat, child_parts): 489 self.pat = re.compile(fnmatch.translate(pat)) 490 _Selector.__init__(self, child_parts) 491 492 def _select_from(self, parent_path, is_dir, exists, listdir): 493 if not is_dir(parent_path): 494 return 495 cf = parent_path._flavour.casefold 496 for name in listdir(parent_path): 497 casefolded = cf(name) 498 if self.pat.match(casefolded): 499 path = parent_path._make_child_relpath(name) 500 for p in self.successor._select_from(path, is_dir, exists, listdir): 501 yield p 502 503 504class _RecursiveWildcardSelector(_Selector): 505 506 def __init__(self, pat, child_parts): 507 _Selector.__init__(self, child_parts) 508 509 def _iterate_directories(self, parent_path, is_dir, listdir): 510 yield parent_path 511 for name in listdir(parent_path): 512 path = parent_path._make_child_relpath(name) 513 if is_dir(path): 514 for p in self._iterate_directories(path, is_dir, listdir): 515 yield p 516 517 def _select_from(self, parent_path, is_dir, exists, listdir): 518 if not is_dir(parent_path): 519 return 520 with _cached(listdir) as listdir: 521 yielded = set() 522 try: 523 successor_select = self.successor._select_from 524 for starting_point in self._iterate_directories(parent_path, is_dir, listdir): 525 for p in successor_select(starting_point, is_dir, exists, listdir): 526 if p not in yielded: 527 yield p 528 yielded.add(p) 529 finally: 530 yielded.clear() 531 532 533# 534# Public API 535# 536 537class _PathParents(Sequence): 538 """This object provides sequence-like access to the logical ancestors 539 of a path. Don't try to construct it yourself.""" 540 __slots__ = ('_pathcls', '_drv', '_root', '_parts') 541 542 def __init__(self, path): 543 # We don't store the instance to avoid reference cycles 544 self._pathcls = type(path) 545 self._drv = path._drv 546 self._root = path._root 547 self._parts = path._parts 548 549 def __len__(self): 550 if self._drv or self._root: 551 return len(self._parts) - 1 552 else: 553 return len(self._parts) 554 555 def __getitem__(self, idx): 556 if idx < 0 or idx >= len(self): 557 raise IndexError(idx) 558 return self._pathcls._from_parsed_parts(self._drv, self._root, 559 self._parts[:-idx - 1]) 560 561 def __repr__(self): 562 return "<{0}.parents>".format(self._pathcls.__name__) 563 564 565class PurePath(object): 566 """PurePath represents a filesystem path and offers operations which 567 don't imply any actual filesystem I/O. Depending on your system, 568 instantiating a PurePath will return either a PurePosixPath or a 569 PureWindowsPath object. You can also instantiate either of these classes 570 directly, regardless of your system. 571 """ 572 __slots__ = ( 573 '_drv', '_root', '_parts', 574 '_str', '_hash', '_pparts', '_cached_cparts', 575 ) 576 577 def __new__(cls, *args): 578 """Construct a PurePath from one or several strings and or existing 579 PurePath objects. The strings and path objects are combined so as 580 to yield a canonicalized path, which is incorporated into the 581 new PurePath object. 582 """ 583 if cls is PurePath: 584 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath 585 return cls._from_parts(args) 586 587 def __reduce__(self): 588 # Using the parts tuple helps share interned path parts 589 # when pickling related paths. 590 return (self.__class__, tuple(self._parts)) 591 592 @classmethod 593 def _parse_args(cls, args): 594 # This is useful when you don't want to create an instance, just 595 # canonicalize some constructor arguments. 596 parts = [] 597 for a in args: 598 if isinstance(a, PurePath): 599 parts += a._parts 600 elif isinstance(a, basestring): 601 parts.append(a) 602 else: 603 raise TypeError( 604 "argument should be a path or str object, not %r" 605 % type(a)) 606 return cls._flavour.parse_parts(parts) 607 608 @classmethod 609 def _from_parts(cls, args, init=True): 610 # We need to call _parse_args on the instance, so as to get the 611 # right flavour. 612 self = object.__new__(cls) 613 drv, root, parts = self._parse_args(args) 614 self._drv = drv 615 self._root = root 616 self._parts = parts 617 if init: 618 self._init() 619 return self 620 621 @classmethod 622 def _from_parsed_parts(cls, drv, root, parts, init=True): 623 self = object.__new__(cls) 624 self._drv = drv 625 self._root = root 626 self._parts = parts 627 if init: 628 self._init() 629 return self 630 631 @classmethod 632 def _format_parsed_parts(cls, drv, root, parts): 633 if drv or root: 634 return drv + root + cls._flavour.join(parts[1:]) 635 else: 636 return cls._flavour.join(parts) 637 638 def _init(self): 639 # Overriden in concrete Path 640 pass 641 642 def _make_child(self, args): 643 drv, root, parts = self._parse_args(args) 644 drv, root, parts = self._flavour.join_parsed_parts( 645 self._drv, self._root, self._parts, drv, root, parts) 646 return self._from_parsed_parts(drv, root, parts) 647 648 def __str__(self): 649 """Return the string representation of the path, suitable for 650 passing to system calls.""" 651 try: 652 return self._str 653 except AttributeError: 654 self._str = self._format_parsed_parts(self._drv, self._root, 655 self._parts) or '.' 656 return self._str 657 658 def as_posix(self): 659 """Return the string representation of the path with forward (/) 660 slashes.""" 661 f = self._flavour 662 return str(self).replace(f.sep, '/') 663 664 def __bytes__(self): 665 """Return the bytes representation of the path. This is only 666 recommended to use under Unix.""" 667 if sys.version_info < (3, 2): 668 raise NotImplementedError("needs Python 3.2 or later") 669 return os.fsencode(str(self)) 670 671 def __repr__(self): 672 return "{0}({1!r})".format(self.__class__.__name__, self.as_posix()) 673 674 def as_uri(self): 675 """Return the path as a 'file' URI.""" 676 if not self.is_absolute(): 677 raise ValueError("relative path can't be expressed as a file URI") 678 return self._flavour.make_uri(self) 679 680 @property 681 def _cparts(self): 682 # Cached casefolded parts, for hashing and comparison 683 try: 684 return self._cached_cparts 685 except AttributeError: 686 self._cached_cparts = self._flavour.casefold_parts(self._parts) 687 return self._cached_cparts 688 689 def __eq__(self, other): 690 if not isinstance(other, PurePath): 691 return NotImplemented 692 return self._cparts == other._cparts and self._flavour is other._flavour 693 694 def __ne__(self, other): 695 return not self == other 696 697 def __hash__(self): 698 try: 699 return self._hash 700 except AttributeError: 701 self._hash = hash(tuple(self._cparts)) 702 return self._hash 703 704 def __lt__(self, other): 705 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 706 return NotImplemented 707 return self._cparts < other._cparts 708 709 def __le__(self, other): 710 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 711 return NotImplemented 712 return self._cparts <= other._cparts 713 714 def __gt__(self, other): 715 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 716 return NotImplemented 717 return self._cparts > other._cparts 718 719 def __ge__(self, other): 720 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 721 return NotImplemented 722 return self._cparts >= other._cparts 723 724 drive = property(attrgetter('_drv'), 725 doc="""The drive prefix (letter or UNC path), if any.""") 726 727 root = property(attrgetter('_root'), 728 doc="""The root of the path, if any.""") 729 730 @property 731 def anchor(self): 732 """The concatenation of the drive and root, or ''.""" 733 anchor = self._drv + self._root 734 return anchor 735 736 @property 737 def name(self): 738 """The final path component, if any.""" 739 parts = self._parts 740 if len(parts) == (1 if (self._drv or self._root) else 0): 741 return '' 742 return parts[-1] 743 744 @property 745 def suffix(self): 746 """The final component's last suffix, if any.""" 747 name = self.name 748 i = name.rfind('.') 749 if 0 < i < len(name) - 1: 750 return name[i:] 751 else: 752 return '' 753 754 @property 755 def suffixes(self): 756 """A list of the final component's suffixes, if any.""" 757 name = self.name 758 if name.endswith('.'): 759 return [] 760 name = name.lstrip('.') 761 return ['.' + suffix for suffix in name.split('.')[1:]] 762 763 @property 764 def stem(self): 765 """The final path component, minus its last suffix.""" 766 name = self.name 767 i = name.rfind('.') 768 if 0 < i < len(name) - 1: 769 return name[:i] 770 else: 771 return name 772 773 def with_name(self, name): 774 """Return a new path with the file name changed.""" 775 if not self.name: 776 raise ValueError("%r has an empty name" % (self,)) 777 return self._from_parsed_parts(self._drv, self._root, 778 self._parts[:-1] + [name]) 779 780 def with_suffix(self, suffix): 781 """Return a new path with the file suffix changed (or added, if none).""" 782 # XXX if suffix is None, should the current suffix be removed? 783 drv, root, parts = self._flavour.parse_parts((suffix,)) 784 if drv or root or len(parts) != 1: 785 raise ValueError("Invalid suffix %r" % (suffix)) 786 suffix = parts[0] 787 if not suffix.startswith('.'): 788 raise ValueError("Invalid suffix %r" % (suffix)) 789 name = self.name 790 if not name: 791 raise ValueError("%r has an empty name" % (self,)) 792 old_suffix = self.suffix 793 if not old_suffix: 794 name = name + suffix 795 else: 796 name = name[:-len(old_suffix)] + suffix 797 return self._from_parsed_parts(self._drv, self._root, 798 self._parts[:-1] + [name]) 799 800 def relative_to(self, *other): 801 """Return the relative path to another path identified by the passed 802 arguments. If the operation is not possible (because this is not 803 a subpath of the other path), raise ValueError. 804 """ 805 # For the purpose of this method, drive and root are considered 806 # separate parts, i.e.: 807 # Path('c:/').relative_to('c:') gives Path('/') 808 # Path('c:/').relative_to('/') raise ValueError 809 if not other: 810 raise TypeError("need at least one argument") 811 parts = self._parts 812 drv = self._drv 813 root = self._root 814 if root: 815 abs_parts = [drv, root] + parts[1:] 816 else: 817 abs_parts = parts 818 to_drv, to_root, to_parts = self._parse_args(other) 819 if to_root: 820 to_abs_parts = [to_drv, to_root] + to_parts[1:] 821 else: 822 to_abs_parts = to_parts 823 n = len(to_abs_parts) 824 cf = self._flavour.casefold_parts 825 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts): 826 formatted = self._format_parsed_parts(to_drv, to_root, to_parts) 827 raise ValueError("{!r} does not start with {!r}" 828 .format(str(self), str(formatted))) 829 return self._from_parsed_parts('', root if n == 1 else '', 830 abs_parts[n:]) 831 832 @property 833 def parts(self): 834 """An object providing sequence-like access to the 835 components in the filesystem path.""" 836 # We cache the tuple to avoid building a new one each time .parts 837 # is accessed. XXX is this necessary? 838 try: 839 return self._pparts 840 except AttributeError: 841 self._pparts = tuple(self._parts) 842 return self._pparts 843 844 def joinpath(self, *args): 845 """Combine this path with one or several arguments, and return a 846 new path representing either a subpath (if all arguments are relative 847 paths) or a totally different path (if one of the arguments is 848 anchored). 849 """ 850 return self._make_child(args) 851 852 def __truediv__(self, key): 853 return self._make_child((key,)) 854 855 def __rtruediv__(self, key): 856 return self._from_parts([key] + self._parts) 857 858 if sys.version_info < (3,): 859 __div__ = __truediv__ 860 __rdiv__ = __rtruediv__ 861 862 @property 863 def parent(self): 864 """The logical parent of the path.""" 865 drv = self._drv 866 root = self._root 867 parts = self._parts 868 if len(parts) == 1 and (drv or root): 869 return self 870 return self._from_parsed_parts(drv, root, parts[:-1]) 871 872 @property 873 def parents(self): 874 """A sequence of this path's logical parents.""" 875 return _PathParents(self) 876 877 def is_absolute(self): 878 """True if the path is absolute (has both a root and, if applicable, 879 a drive).""" 880 if not self._root: 881 return False 882 return not self._flavour.has_drv or bool(self._drv) 883 884 def is_reserved(self): 885 """Return True if the path contains one of the special names reserved 886 by the system, if any.""" 887 return self._flavour.is_reserved(self._parts) 888 889 def match(self, path_pattern): 890 """ 891 Return True if this path matches the given pattern. 892 """ 893 cf = self._flavour.casefold 894 path_pattern = cf(path_pattern) 895 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,)) 896 if not pat_parts: 897 raise ValueError("empty pattern") 898 if drv and drv != cf(self._drv): 899 return False 900 if root and root != cf(self._root): 901 return False 902 parts = self._cparts 903 if drv or root: 904 if len(pat_parts) != len(parts): 905 return False 906 pat_parts = pat_parts[1:] 907 elif len(pat_parts) > len(parts): 908 return False 909 for part, pat in zip(reversed(parts), reversed(pat_parts)): 910 if not fnmatch.fnmatchcase(part, pat): 911 return False 912 return True 913 914 915class PurePosixPath(PurePath): 916 _flavour = _posix_flavour 917 __slots__ = () 918 919 920class PureWindowsPath(PurePath): 921 _flavour = _windows_flavour 922 __slots__ = () 923 924 925# Filesystem-accessing classes 926 927 928class Path(PurePath): 929 __slots__ = ( 930 '_accessor', 931 ) 932 933 def __new__(cls, *args, **kwargs): 934 if cls is Path: 935 cls = WindowsPath if os.name == 'nt' else PosixPath 936 self = cls._from_parts(args, init=False) 937 if not self._flavour.is_supported: 938 raise NotImplementedError("cannot instantiate %r on your system" 939 % (cls.__name__,)) 940 self._init() 941 return self 942 943 def _init(self, 944 # Private non-constructor arguments 945 template=None, 946 ): 947 if template is not None: 948 self._accessor = template._accessor 949 else: 950 self._accessor = _normal_accessor 951 952 def _make_child_relpath(self, part): 953 # This is an optimization used for dir walking. `part` must be 954 # a single part relative to this path. 955 parts = self._parts + [part] 956 return self._from_parsed_parts(self._drv, self._root, parts) 957 958 def _opener(self, name, flags, mode=0o666): 959 # A stub for the opener argument to built-in open() 960 return self._accessor.open(self, flags, mode) 961 962 def _raw_open(self, flags, mode=0o777): 963 """ 964 Open the file pointed by this path and return a file descriptor, 965 as os.open() does. 966 """ 967 return self._accessor.open(self, flags, mode) 968 969 # Public API 970 971 @classmethod 972 def cwd(cls): 973 """Return a new path pointing to the current working directory 974 (as returned by os.getcwd()). 975 """ 976 return cls(os.getcwd()) 977 978 def iterdir(self): 979 """Iterate over the files in this directory. Does not yield any 980 result for the special paths '.' and '..'. 981 """ 982 for name in self._accessor.listdir(self): 983 if name in ('.', '..'): 984 # Yielding a path object for these makes little sense 985 continue 986 yield self._make_child_relpath(name) 987 988 def glob(self, pattern): 989 """Iterate over this subtree and yield all existing files (of any 990 kind, including directories) matching the given pattern. 991 """ 992 pattern = self._flavour.casefold(pattern) 993 drv, root, pattern_parts = self._flavour.parse_parts((pattern,)) 994 if drv or root: 995 raise NotImplementedError("Non-relative patterns are unsupported") 996 selector = _make_selector(tuple(pattern_parts)) 997 for p in selector.select_from(self): 998 yield p 999 1000 def rglob(self, pattern): 1001 """Recursively yield all existing files (of any kind, including 1002 directories) matching the given pattern, anywhere in this subtree. 1003 """ 1004 pattern = self._flavour.casefold(pattern) 1005 drv, root, pattern_parts = self._flavour.parse_parts((pattern,)) 1006 if drv or root: 1007 raise NotImplementedError("Non-relative patterns are unsupported") 1008 selector = _make_selector(("**",) + tuple(pattern_parts)) 1009 for p in selector.select_from(self): 1010 yield p 1011 1012 def absolute(self): 1013 """Return an absolute version of this path. This function works 1014 even if the path doesn't point to anything. 1015 1016 No normalization is done, i.e. all '.' and '..' will be kept along. 1017 Use resolve() to get the canonical path to a file. 1018 """ 1019 # XXX untested yet! 1020 if self.is_absolute(): 1021 return self 1022 # FIXME this must defer to the specific flavour (and, under Windows, 1023 # use nt._getfullpathname()) 1024 obj = self._from_parts([os.getcwd()] + self._parts, init=False) 1025 obj._init(template=self) 1026 return obj 1027 1028 def resolve(self): 1029 """ 1030 Make the path absolute, resolving all symlinks on the way and also 1031 normalizing it (for example turning slashes into backslashes under 1032 Windows). 1033 """ 1034 s = self._flavour.resolve(self) 1035 if s is None: 1036 # No symlink resolution => for consistency, raise an error if 1037 # the path doesn't exist or is forbidden 1038 self.stat() 1039 s = str(self.absolute()) 1040 # Now we have no symlinks in the path, it's safe to normalize it. 1041 normed = self._flavour.pathmod.normpath(s) 1042 obj = self._from_parts((normed,), init=False) 1043 obj._init(template=self) 1044 return obj 1045 1046 def stat(self): 1047 """ 1048 Return the result of the stat() system call on this path, like 1049 os.stat() does. 1050 """ 1051 return self._accessor.stat(self) 1052 1053 def owner(self): 1054 """ 1055 Return the login name of the file owner. 1056 """ 1057 import pwd 1058 return pwd.getpwuid(self.stat().st_uid).pw_name 1059 1060 def group(self): 1061 """ 1062 Return the group name of the file gid. 1063 """ 1064 import grp 1065 return grp.getgrgid(self.stat().st_gid).gr_name 1066 1067 def open(self, mode='r', buffering=-1, encoding=None, 1068 errors=None, newline=None): 1069 """ 1070 Open the file pointed by this path and return a file object, as 1071 the built-in open() function does. 1072 """ 1073 if sys.version_info >= (3, 3): 1074 return io.open(str(self), mode, buffering, encoding, errors, newline, 1075 opener=self._opener) 1076 else: 1077 return io.open(str(self), mode, buffering, encoding, errors, newline) 1078 1079 def touch(self, mode=0o666, exist_ok=True): 1080 """ 1081 Create this file with the given access mode, if it doesn't exist. 1082 """ 1083 if exist_ok: 1084 # First try to bump modification time 1085 # Implementation note: GNU touch uses the UTIME_NOW option of 1086 # the utimensat() / futimens() functions. 1087 t = time.time() 1088 try: 1089 self._accessor.utime(self, (t, t)) 1090 except OSError: 1091 # Avoid exception chaining 1092 pass 1093 else: 1094 return 1095 flags = os.O_CREAT | os.O_WRONLY 1096 if not exist_ok: 1097 flags |= os.O_EXCL 1098 fd = self._raw_open(flags, mode) 1099 os.close(fd) 1100 1101 def mkdir(self, mode=0o777, parents=False): 1102 if not parents: 1103 self._accessor.mkdir(self, mode) 1104 else: 1105 try: 1106 self._accessor.mkdir(self, mode) 1107 except OSError as e: 1108 if e.errno != ENOENT: 1109 raise 1110 self.parent.mkdir(parents=True) 1111 self._accessor.mkdir(self, mode) 1112 1113 def chmod(self, mode): 1114 """ 1115 Change the permissions of the path, like os.chmod(). 1116 """ 1117 self._accessor.chmod(self, mode) 1118 1119 def lchmod(self, mode): 1120 """ 1121 Like chmod(), except if the path points to a symlink, the symlink's 1122 permissions are changed, rather than its target's. 1123 """ 1124 self._accessor.lchmod(self, mode) 1125 1126 def unlink(self): 1127 """ 1128 Remove this file or link. 1129 If the path is a directory, use rmdir() instead. 1130 """ 1131 self._accessor.unlink(self) 1132 1133 def rmdir(self): 1134 """ 1135 Remove this directory. The directory must be empty. 1136 """ 1137 self._accessor.rmdir(self) 1138 1139 def lstat(self): 1140 """ 1141 Like stat(), except if the path points to a symlink, the symlink's 1142 status information is returned, rather than its target's. 1143 """ 1144 return self._accessor.lstat(self) 1145 1146 def rename(self, target): 1147 """ 1148 Rename this path to the given path. 1149 """ 1150 self._accessor.rename(self, target) 1151 1152 def replace(self, target): 1153 """ 1154 Rename this path to the given path, clobbering the existing 1155 destination if it exists. 1156 """ 1157 if sys.version_info < (3, 3): 1158 raise NotImplementedError("replace() is only available " 1159 "with Python 3.3 and later") 1160 self._accessor.replace(self, target) 1161 1162 def symlink_to(self, target, target_is_directory=False): 1163 """ 1164 Make this path a symlink pointing to the given path. 1165 Note the order of arguments (self, target) is the reverse of os.symlink's. 1166 """ 1167 self._accessor.symlink(target, self, target_is_directory) 1168 1169 # Convenience functions for querying the stat results 1170 1171 def exists(self): 1172 """ 1173 Whether this path exists. 1174 """ 1175 try: 1176 self.stat() 1177 except OSError as e: 1178 if e.errno != ENOENT: 1179 raise 1180 return False 1181 return True 1182 1183 def is_dir(self): 1184 """ 1185 Whether this path is a directory. 1186 """ 1187 try: 1188 return S_ISDIR(self.stat().st_mode) 1189 except OSError as e: 1190 if e.errno != ENOENT: 1191 raise 1192 # Path doesn't exist or is a broken symlink 1193 # (see https://bitbucket.org/pitrou/pathlib/issue/12/) 1194 return False 1195 1196 def is_file(self): 1197 """ 1198 Whether this path is a regular file (also True for symlinks pointing 1199 to regular files). 1200 """ 1201 try: 1202 return S_ISREG(self.stat().st_mode) 1203 except OSError as e: 1204 if e.errno != ENOENT: 1205 raise 1206 # Path doesn't exist or is a broken symlink 1207 # (see https://bitbucket.org/pitrou/pathlib/issue/12/) 1208 return False 1209 1210 def is_symlink(self): 1211 """ 1212 Whether this path is a symbolic link. 1213 """ 1214 try: 1215 return S_ISLNK(self.lstat().st_mode) 1216 except OSError as e: 1217 if e.errno != ENOENT: 1218 raise 1219 # Path doesn't exist 1220 return False 1221 1222 def is_block_device(self): 1223 """ 1224 Whether this path is a block device. 1225 """ 1226 try: 1227 return S_ISBLK(self.stat().st_mode) 1228 except OSError as e: 1229 if e.errno != ENOENT: 1230 raise 1231 # Path doesn't exist or is a broken symlink 1232 # (see https://bitbucket.org/pitrou/pathlib/issue/12/) 1233 return False 1234 1235 def is_char_device(self): 1236 """ 1237 Whether this path is a character device. 1238 """ 1239 try: 1240 return S_ISCHR(self.stat().st_mode) 1241 except OSError as e: 1242 if e.errno != ENOENT: 1243 raise 1244 # Path doesn't exist or is a broken symlink 1245 # (see https://bitbucket.org/pitrou/pathlib/issue/12/) 1246 return False 1247 1248 def is_fifo(self): 1249 """ 1250 Whether this path is a FIFO. 1251 """ 1252 try: 1253 return S_ISFIFO(self.stat().st_mode) 1254 except OSError as e: 1255 if e.errno != ENOENT: 1256 raise 1257 # Path doesn't exist or is a broken symlink 1258 # (see https://bitbucket.org/pitrou/pathlib/issue/12/) 1259 return False 1260 1261 def is_socket(self): 1262 """ 1263 Whether this path is a socket. 1264 """ 1265 try: 1266 return S_ISSOCK(self.stat().st_mode) 1267 except OSError as e: 1268 if e.errno != ENOENT: 1269 raise 1270 # Path doesn't exist or is a broken symlink 1271 # (see https://bitbucket.org/pitrou/pathlib/issue/12/) 1272 return False 1273 1274 1275class PosixPath(Path, PurePosixPath): 1276 __slots__ = () 1277 1278class WindowsPath(Path, PureWindowsPath): 1279 __slots__ = () 1280 1281