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