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